<template>
  <div class="app-container">
    <el-card class="box-card">
      <template #header>
        <div class="clearfix">
        <span style="font-size: 20px;font-weight: bold;">设备工作波形示教</span>
        <div style="float: right;">
          <span style="margin-right: 15px;">春晓基地</span>
          <el-button icon="el-icon-bell" size="mini" circle plain></el-button>
          <el-button icon="el-icon-full-screen" size="mini" type="primary" plain @click="toIndex">大屏展示</el-button>
        </div>
      </div>
      </template>

      <el-row :gutter="24">
        <!-- 设备信息面板 -->
        <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="6">
          <div class="device-info-panel">
            <div class="device-header">
              <div class="device-shape-container">
                <div class="device-shape" :class="['shape-' + getDeviceShape(effectiveDeviceTypeForThresholds), deviceInfo.status]">
                  <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
                    <path :d="getDeviceShapePath(effectiveDeviceTypeForThresholds)" fill="currentColor"/>
                  </svg>
                </div>
              </div>
              <div class="device-name">
                {{ deviceInfo.name }}
                <div class="device-no">编号: {{ deviceInfo.number }}</div>
              </div>
            </div>

            <div class="info-list">
              <div class="info-item">
                <span class="label">品牌:</span>
                <span class="value">{{ deviceInfo.brand || '未知' }}</span>
              </div>
              <div class="info-item">
                <span class="label">型号:</span>
                <span class="value">{{ deviceInfo.model || '未知' }}</span>
              </div>
              <div class="info-item">
                <span class="label">类型:</span>
                <span class="value">{{ effectiveDeviceTypeForThresholds || '未知' }}</span>
              </div>
              <div class="info-item">
                <span class="label">动作数:
                  <el-tooltip content="设备定义的标准操作循环次数" placement="top">
                    <i class="el-icon-info info-icon"></i>
                  </el-tooltip>
                </span>
                <span class="value">{{ deviceInfo.actions != null ? deviceInfo.actions : '未知' }}</span>
              </div>
            </div>

            <div class="status-panel">
              <div class="status-tag"
                   :class="[deviceInfo.status, deviceInfo.status === 'error' ? 'error-highlight' : '']">
                {{ {'normal': '正常', 'warning': '注意', 'error': '故障'}[deviceInfo.status] || '未知状态' }}
              </div>

              <div class="device-details">
                <div class="detail-item">
                  <span>效率排名: {{ deviceInfo.rank || 'N/A' }}</span>
                </div>
                <div class="detail-item">
                  <span>今日计划: {{ deviceInfo.planHours != null ? deviceInfo.planHours + ' 小时' : '未设定' }}</span>
                </div>
                <div class="detail-item">
                  <span>已运行: {{ formatRunHours(deviceInfo.runHours) }}</span>
                </div>
              </div>
            </div>

            <div class="action-bar">
              <el-button size="small" plain icon="el-icon-warning">报修</el-button>
              <el-button size="small" plain icon="el-icon-s-claim">维护</el-button>
              <el-button size="small" plain icon="el-icon-edit">编辑</el-button>
            </div>

            <!-- 添加波形数据类型选择 -->
            <div class="wave-select-panel">
              <div class="panel-title">波形数据选择</div>
              <div class="data-selector">
                <div class="axis-title">数据类型:</div>
                <el-radio-group v-model="dataType" size="small" @change="switchDataType">
                  <el-radio-button label="rms">均方根(RMS)</el-radio-button>
                  <el-radio-button label="peak">峰值(Peak)</el-radio-button>
                </el-radio-group>
              </div>
              <!-- 新增传感器选择器 -->
              <div class="data-selector" style="margin-top: 10px;">
                <div class="axis-title">传感器:</div>
                <el-select v-model="currentPosition" size="small" @change="switchSensor" placeholder="选择传感器"
                           v-if="devicePositions.length > 0">
                  <el-option v-for="position in devicePositions"
                             :key="position"
                             :label="position"
                             :value="position">
                  </el-option>
                </el-select>
                <span v-else style="color: #909399; font-size: 13px">暂无传感器信息</span>
              </div>
              <!-- 显示模式已固定为三轴合并 -->
            </div>
            <!-- 设备停机时间面板 -->
            <div class="downtime-panel">
              <div class="panel-title">
                <div>
                  <i class="el-icon-time"></i>
                  <span>设备停机时间</span>
                </div>
                <el-button
                  type="primary"
                  size="mini"
                  icon="el-icon-edit"
                  plain
                  @click="toDowntimeEntry">录入停机信息
                </el-button>
              </div>
              <div class="downtime-summary">
                <div class="downtime-card">
                  <div class="downtime-value">2.5
                    <span class="downtime-unit">小时</span>
                  </div>
                  <div class="downtime-label">今日停机</div>
                  <el-progress
                    :percentage="10"
                    :color="[{color: '#67C23A', percentage: 5}, {color: '#E6A23C', percentage: 15}, {color: '#F56C6C', percentage: 100}]"
                    :show-text="false"
                    :stroke-width="4">
                  </el-progress>
                </div>
                <div class="downtime-card">
                  <div class="downtime-value">12
                    <span class="downtime-unit">小时</span>
                  </div>
                  <div class="downtime-label">本周停机</div>
                  <el-progress
                    :percentage="7"
                    :color="[{color: '#67C23A', percentage: 10}, {color: '#E6A23C', percentage: 25}, {color: '#F56C6C', percentage: 100}]"
                    :show-text="false"
                    :stroke-width="4">
                  </el-progress>
                </div>
                <div class="downtime-card">
                  <div class="downtime-value">36
                    <span class="downtime-unit">小时</span>
                  </div>
                  <div class="downtime-label">本月停机</div>
                  <el-progress
                    :percentage="5"
                    :color="[{color: '#67C23A', percentage: 8}, {color: '#E6A23C', percentage: 20}, {color: '#F56C6C', percentage: 100}]"
                    :show-text="false"
                    :stroke-width="4">
                  </el-progress>
                </div>
              </div>

              <!-- 最近停机记录 -->
              <div class="downtime-records">
                <div class="records-header">
                  <span>最近停机记录</span>
                  <el-button type="text" size="mini" icon="el-icon-more" @click="showMoreDowntimeRecords">更多
                  </el-button>
                </div>
                <div class="record-list">
                  <div class="record-item">
                    <div class="record-icon maintenance">
                      <i class="el-icon-s-tools"></i>
                    </div>
                    <div class="record-info">
                      <div class="record-time">4.5 小时</div>
                      <div class="record-reason">计划维护 - 更换主轴承</div>
                      <div class="record-date">2023-05-20</div>
                    </div>
                  </div>
                  <div class="record-item">
                    <div class="record-icon failure">
                      <i class="el-icon-error"></i>
                    </div>
                    <div class="record-info">
                      <div class="record-time">8 小时</div>
                      <div class="record-reason">控制系统故障</div>
                      <div class="record-date">2023-05-15</div>
                    </div>
                  </div>
                  <div class="record-item">
                    <div class="record-icon other">
                      <i class="el-icon-info"></i>
                    </div>
                    <div class="record-info">
                      <div class="record-time">1.5 小时</div>
                      <div class="record-reason">电力中断</div>
                      <div class="record-date">2023-05-10</div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </el-col>

        <!-- 右侧波形图 -->
        <el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="18">
          <!-- 使用扁平化日期选择器 -->
          <flat-date-picker
            v-model="dateRange"
            title="选择波形数据时间范围"
            @search="handleDateRangeChange"
          />

          <div class="waveform-panel">
            <div class="waveform-header">
              <div class="waveform-title">{{ waveformTitle }}</div>
              <div class="waveform-controls">
                <el-button type="primary" plain size="small" class="wave-lib-btn">本机示教波纹库</el-button>
                <el-button
                           type="warning"
                           plain
                           size="small"
                           @click="recreateChart"
                           title="如果图表无法正常显示，点击此按钮重建图表">重建图表
                </el-button>
                <el-button type="success" plain size="small" @click="openHighlightDialog" title="在新窗口中分析阈值高亮">阈值高亮分析</el-button>

                <el-tooltip placement="top-start" effect="light" popper-class="fullscreen-tooltip">
                  <template #content>
                    <div style="font-weight:bold;margin-bottom:8px;color:#409EFF;">全屏操作说明：</div>
                    <div style="margin-bottom:6px;"><span style="color:#409EFF;font-weight:bold;">第一步:</span> 用
                      <span class="key-icon">↑</span><span class="key-icon">↓</span> 键放大/缩小波形
                    </div>
                    <div><span style="color:#409EFF;font-weight:bold;">第二步:</span> 用 <span class="key-icon">←</span><span
                      class="key-icon">→</span> 键左右移动查看细节
                    </div>
                  </template>
                  <el-button type="info" icon="el-icon-full-screen" plain size="small" @click="toggleFullscreen">
                    {{ isFullscreen ? '退出全屏' : '全屏查看' }}
                  </el-button>
                </el-tooltip>

                <el-button type="danger" plain size="small" @click="createTestChart" title="创建测试图表">测试图表
                </el-button>
                <el-button type="info" plain size="small" @click="showPerformanceStats" title="查看数据请求性能统计">性能统计
                </el-button>
                <el-tag v-if="largeDataDevices.includes(deviceId)" type="warning" size="small" title="此设备数据量较大，已启用优化加载">
                  大数据量
                </el-tag>
              </div>
            </div>

            <div class="waveform-chart" ref="mainChart"></div>

            <!-- 加载历史数据提示遮罩 -->
            <div v-if="loadingHistoricalData" class="loading-data-overlay">
              <div class="loading-icon">
                <i class="el-icon-loading"></i>
              </div>
              <div class="loading-title">
                <span v-if="loadingCompleteHistory">加载完整历史数据</span>
                <span v-else>加载特定时段历史数据</span>
              </div>
              <p class="loading-description">
                <template v-if="loadingCompleteHistory">正在获取所有历史振动数据，请稍候...</template>
                <template v-else>正在获取所选时间范围内的振动数据，请稍候...</template>
              </p>
              <div class="loading-progress" v-if="loadingProgress > 0">
                <el-progress
                  :percentage="loadingProgress"
                  :stroke-width="8"
                  :show-text="false"
                  :color="[
                    {color: '#e6a23c', percentage: 20},
                    {color: '#67C23A', percentage: 50},
                    {color: '#409EFF', percentage: 100}
                  ]">
                </el-progress>
                <span class="progress-text">{{ loadingProgress }}%</span>
              </div>
              <div class="loading-tip" v-if="FirstTimeLoad && loadingCompleteHistory">
                <i class="el-icon-info"></i>
                <span>首次加载可能需要较长时间，请耐心等待</span>
              </div>
            </div>

            <!-- 阈值设置面板 -->
            <div class="threshold-controls" v-if="!noDataAvailable">
              <div class="panel-title" style="display: flex; align-items: center; justify-content: space-between;">
                <div class="title-content">
                  <i class="el-icon-warning-outline"></i>
                  <span>设备振动阈值设置</span>
                </div>
                <el-button
                  :icon="thresholdSettingsPanelVisible ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
                  type="text"
                  @click="toggleThresholdSettingsPanel"
                  size="mini"
                  class="toggle-btn"
                  title="切换显示/隐藏"
                ></el-button>
              </div>
              <div v-show="!thresholdSettingsPanelVisible" class="threshold-panel-content">
                <!-- 更新后的阈值设置面板 -->
                <div class="threshold-settings-container">
                  <div class="device-type-info">
                    <i class="el-icon-cpu"></i>
                    <!-- 修改设备类型显示 -->
                    <span>当前操作的设备类型: <strong>{{ effectiveDeviceTypeForThresholds }}</strong></span>
                    <el-tooltip content="系统会优先使用设备信息中的'类型'字段。如果该字段无效或为'未知类型'/'default'，则会尝试从设备'名称'中提取中文部分作为操作类型。每种设备类型有不同的振动阈值标准。" placement="top">
                      <i class="el-icon-info info-icon"></i>
                    </el-tooltip>
                  </div>

                  <div class="threshold-tabs">
                    <el-tabs :key="thresholdsDisplayKey" type="border-card" class="custom-tabs">
                      <!-- X轴阈值设置 -->
                      <el-tab-pane>
                        <template #label>
                          <div class="axis-label">
                            <span class="axis-color-dot" :style="{ backgroundColor: thresholds.x.color }"></span>
                            <span>X轴阈值</span>
                          </div>
                        </template>
                        <div class="threshold-content">
                          <div class="threshold-value-container">
                            <div class="threshold-item">
                              <template v-if="dataType === 'rms'">
                                <span class="threshold-label">RMS阈值:</span>
                                <el-input-number
                                  :key="'x-rms-' + thresholdsDisplayKey"
                                  v-model="thresholds.x.value"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                              <template v-else>
                                <span class="threshold-label">峰值阈值:</span>
                                <el-input-number
                                  :key="'x-peak-' + thresholdsDisplayKey"
                                  v-model="thresholds.x.peakValue"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                            </div>

                            <div class="threshold-item">
                              <span class="threshold-label">高亮颜色:</span>
                              <el-color-picker
                                v-model="thresholds.x.color"
                                size="small"
                                class="custom-color-picker"
                                :predefine="['#F56C6C', '#E6A23C', '#409EFF', '#67C23A', '#FC427B', '#55E6C1']"
                                @change="updateChartVisualization">
                              </el-color-picker>
                              <div class="color-preview" :style="{ backgroundColor: thresholds.x.color }"></div>
                            </div>
                          </div>

                          <div class="threshold-description">
                            <i class="el-icon-info"></i>
                            <span>当X轴振动值超过此阈值时，将在图表中以高亮颜色显示</span>
                          </div>

                          <div class="threshold-effect-preview">
                            <span class="preview-label">效果预览:</span>
                            <div class="line-preview">
                              <div class="line-normal"></div>
                              <div class="line-highlight" :style="{ backgroundColor: thresholds.x.color }"></div>
                            </div>
                          </div>
                        </div>
                      </el-tab-pane>

                      <!-- Y轴阈值设置 -->
                      <el-tab-pane>
                        <template #label>
                          <div class="axis-label">
                            <span class="axis-color-dot" :style="{ backgroundColor: thresholds.y.color }"></span>
                            <span>Y轴阈值</span>
                          </div>
                        </template>
                        <div class="threshold-content">
                          <div class="threshold-value-container">
                            <div class="threshold-item">
                              <template v-if="dataType === 'rms'">
                                <span class="threshold-label">RMS阈值:</span>
                                <el-input-number
                                  :key="'y-rms-' + thresholdsDisplayKey"
                                  v-model="thresholds.y.value"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                              <template v-else>
                                <span class="threshold-label">峰值阈值:</span>
                                <el-input-number
                                  :key="'y-peak-' + thresholdsDisplayKey"
                                  v-model="thresholds.y.peakValue"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                            </div>

                            <div class="threshold-item">
                              <span class="threshold-label">高亮颜色:</span>
                              <el-color-picker
                                v-model="thresholds.y.color"
                                size="small"
                                class="custom-color-picker"
                                :predefine="['#F56C6C', '#E6A23C', '#409EFF', '#67C23A', '#FC427B', '#55E6C1']"
                                @change="updateChartVisualization">
                              </el-color-picker>
                              <div class="color-preview" :style="{ backgroundColor: thresholds.y.color }"></div>
                            </div>
                          </div>

                          <div class="threshold-description">
                            <i class="el-icon-info"></i>
                            <span>当Y轴振动值超过此阈值时，将在图表中以高亮颜色显示</span>
                          </div>

                          <div class="threshold-effect-preview">
                            <span class="preview-label">效果预览:</span>
                            <div class="line-preview">
                              <div class="line-normal"></div>
                              <div class="line-highlight" :style="{ backgroundColor: thresholds.y.color }"></div>
                            </div>
                          </div>
                        </div>
                      </el-tab-pane>

                      <!-- Z轴阈值设置 -->
                      <el-tab-pane>
                        <template #label>
                          <div class="axis-label">
                            <span class="axis-color-dot" :style="{ backgroundColor: thresholds.z.color }"></span>
                            <span>Z轴阈值</span>
                          </div>
                        </template>
                        <div class="threshold-content">
                          <div class="threshold-value-container">
                            <div class="threshold-item">
                              <template v-if="dataType === 'rms'">
                                <span class="threshold-label">RMS阈值:</span>
                                <el-input-number
                                  :key="'z-rms-' + thresholdsDisplayKey"
                                  v-model="thresholds.z.value"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                              <template v-else>
                                <span class="threshold-label">峰值阈值:</span>
                                <el-input-number
                                  :key="'z-peak-' + thresholdsDisplayKey"
                                  v-model="thresholds.z.peakValue"
                                  :precision="2"
                                  :step="0.1"
                                  :min="0"
                                  size="small"
                                  class="custom-input-number"
                                  @change="updateChartVisualization">
                                </el-input-number>
                                <span class="threshold-unit">m/s²</span>
                              </template>
                            </div>

                            <div class="threshold-item">
                              <span class="threshold-label">高亮颜色:</span>
                              <el-color-picker
                                v-model="thresholds.z.color"
                                size="small"
                                class="custom-color-picker"
                                :predefine="['#F56C6C', '#E6A23C', '#409EFF', '#67C23A', '#FC427B', '#55E6C1']"
                                @change="updateChartVisualization">
                              </el-color-picker>
                              <div class="color-preview" :style="{ backgroundColor: thresholds.z.color }"></div>
                            </div>
                          </div>

                          <div class="threshold-description">
                            <i class="el-icon-info"></i>
                            <span>当Z轴振动值超过此阈值时，将在图表中以高亮颜色显示</span>
                          </div>

                          <div class="threshold-effect-preview">
                            <span class="preview-label">效果预览:</span>
                            <div class="line-preview">
                              <div class="line-normal"></div>
                              <div class="line-highlight" :style="{ backgroundColor: thresholds.z.color }"></div>
                            </div>
                          </div>
                        </div>
                      </el-tab-pane>
                    </el-tabs>
                  </div>

                  <div class="threshold-actions">
                    <el-button size="small" type="primary" @click="applyThresholds" icon="el-icon-check" class="action-button apply-btn">应用阈值</el-button>
                    <el-button size="small" @click="resetThresholds" icon="el-icon-refresh-left" class="action-button reset-btn">重置</el-button>
                    <el-button size="small" type="success" @click="saveThresholds" icon="el-icon-star-off" class="action-button save-btn">保存为设备默认值</el-button>
                    <el-button size="small" type="info" @click="loadDefaultThresholds" icon="el-icon-download" class="action-button load-btn">读取数据库默认值</el-button>
                  </div>

                  <div class="threshold-info-panel">
                    <div class="info-title">
                      <i class="el-icon-info"></i>
                      <span>阈值设置说明</span>
                    </div>
                    <div class="info-content">
                      <p>1. 振动阈值用于标识设备振动的警戒水平，超过阈值可能表明设备需要维护或存在故障风险</p>
                      <p>2. 不同类型设备应使用不同的阈值标准，可通过"读取数据库默认值"按钮加载推荐阈值</p>
                      <p>3. 保存为设备默认值后，下次访问将自动应用这些阈值设置</p>
                    </div>
                  </div>
                </div>
              </div> <!-- Closing v-show div -->
            </div>

            <!-- 无数据提示 -->
            <div v-if="noDataAvailable" class="no-data-tip">
              <i class="el-icon-warning-outline"></i>
              <p>暂无符合条件的振动数据</p>
              <el-button type="primary" plain size="small" @click="refreshData" icon="el-icon-refresh">刷新数据
              </el-button>
            </div>

            <!-- 关键数据仪表盘 -->
            <div class="dashboard-panel">
              <div class="dashboard-title">
                <i class="el-icon-data-analysis"></i>
                <span>设备运行状态</span>
                <!-- <span style="font-size:12px;color:#bbb;margin-left:8px;">待开发</span> -->
                <!-- Removed '待开发' span -->
              </div>
              <el-row :gutter="20" class="gauge-panel">
                <el-col :xs="24" :sm="12" :md="12">
                  <div class="gauge-item">
                    <el-progress type="dashboard" :percentage="parseWorkRate(deviceInfo.workRate)"
                                 :color="[{color: '#f56c6c', percentage: 20}, {color: '#e6a23c', percentage: 50}, {color: '#67C23A', percentage: 100}]"
                                 :width="100" :stroke-width="8">
                      <template #default="{ percentage }">
                        <span class="percentage-value">{{ percentage }}%</span>
                        <span class="percentage-label">开工率</span>
                      </template>
                    </el-progress>
                    <div class="gauge-description">设备实际工作时间占总时间的比例</div>
                  </div>
                </el-col>
                <el-col :xs="24" :sm="12" :md="12">
                  <div class="gauge-item">
                    <el-progress type="dashboard" :percentage="progressPercentage"
                                 :color="[{color: '#f56c6c', percentage: 20}, {color: '#e6a23c', percentage: 60}, {color: '#409EFF', percentage: 100}]"
                                 :width="100" :stroke-width="8">
                      <template #default="{ percentage }">
                        <span class="percentage-value">{{ percentage }}%</span>
                        <span class="percentage-label">计划完成</span>
                      </template>
                    </el-progress>
                    <div class="gauge-description">当前已完成工作计划的百分比</div>
                  </div>
                </el-col>
              </el-row>
            </div>
          </div>
        </el-col>
      </el-row>

    </el-card>
    <el-dialog
      title="阈值高亮分析"
      :visible.sync="highlightDialogVisible"
      width="70%"
      :modal-append-to-body="false"
      @closed="handleHighlightDialogClosed"
      center
    >
      <div ref="highlightChartContainer" style="width: 100%; height: 500px;"></div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="highlightDialogVisible = false">关 闭</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import {getDevice} from '@/api/gelly/device'
import {getDeviceWaveforms, getWaveformDataByrangeTime, getWaveformDataNoAuth, getThresholdByDeviceType, addThreshold, updateThreshold,getDeviceTimeRange} from '@/api/real/waveform' // 添加无权限版本API
import {getAccelerationData} from '@/api/real/detect'
import FlatDatePicker from '@/components/FlatDatePicker'
import RealtimeWaveformManager from '@/utils/realtimeWaveformManager'
import { mapGetters } from 'vuex'

// 数据请求优化管理器
class DataRequestManager {
  constructor() {
    this.cache = new Map() // 请求缓存
    this.pendingRequests = new Map() // 正在进行的请求
    this.cacheTimeout = 5 * 60 * 1000 // 5分钟缓存
    this.requestTimeout = 120000 // 2分钟请求超时，与全局配置一致
    this.maxRetries = 3 // 最大重试次数
    this.retryDelay = 2000 // 重试延迟（毫秒）
    this.stats = {
      totalRequests: 0,
      cacheHits: 0,
      duplicateRequests: 0,
      requestTimes: [],
      retries: 0,
      timeouts: 0
    }
  }

  // 生成缓存键
  generateCacheKey(apiName, params) {
    return `${apiName}_${JSON.stringify(params)}`
  }

  // 检查缓存是否有效
  isCacheValid(cacheItem) {
    return cacheItem && (Date.now() - cacheItem.timestamp) < this.cacheTimeout
  }

  // 获取缓存数据
  getFromCache(cacheKey) {
    const cacheItem = this.cache.get(cacheKey)
    if (this.isCacheValid(cacheItem)) {
      console.log('【数据缓存】命中缓存:', cacheKey)
      this.stats.cacheHits++
      return cacheItem.data
    }
    return null
  }

  // 设置缓存
  setCache(cacheKey, data) {
    this.cache.set(cacheKey, {
      data,
      timestamp: Date.now()
    })
    console.log('【数据缓存】设置缓存:', cacheKey)
  }

  // 请求去重处理（带重试机制）
  async request(apiName, apiFunction, params = {}) {
    const cacheKey = this.generateCacheKey(apiName, params)
    const startTime = Date.now()

    this.stats.totalRequests++

    // 检查缓存
    const cachedData = this.getFromCache(cacheKey)
    if (cachedData) {
      return cachedData
    }

    // 检查是否有相同的请求正在进行
    if (this.pendingRequests.has(cacheKey)) {
      console.log('【请求去重】等待进行中的请求:', cacheKey)
      this.stats.duplicateRequests++
      return await this.pendingRequests.get(cacheKey)
    }

    // 发起新请求（带重试机制）
    console.log('【数据请求】发起新请求:', cacheKey)
    const requestPromise = this.executeWithRetry(apiFunction, params, apiName)
      .then(response => {
        const endTime = Date.now()
        this.stats.requestTimes.push(endTime - startTime)
        this.setCache(cacheKey, response)
        this.pendingRequests.delete(cacheKey)
        return response
      })
      .catch(error => {
        this.pendingRequests.delete(cacheKey)
        throw error
      })

    this.pendingRequests.set(cacheKey, requestPromise)
    return await requestPromise
  }

  // 带重试的请求执行
  async executeWithRetry(apiFunction, params, apiName, retryCount = 0) {
    try {
      // 创建超时Promise
      const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => {
          this.stats.timeouts++
          reject(new Error(`请求超时 (${this.requestTimeout}ms): ${apiName}`))
        }, this.requestTimeout)
      })

      // 执行API请求
      const response = await Promise.race([
        apiFunction(params),
        timeoutPromise
      ])

      console.log(`【请求成功】${apiName} - 尝试次数: ${retryCount + 1}`)
      return response

    } catch (error) {
      console.error(`【请求失败】${apiName} - 尝试次数: ${retryCount + 1}`, error.message)

      // 检查是否为权限错误，尝试降级
      if (this.isAuthError(error) && retryCount === 0) {
        console.log(`【权限降级】检测到权限错误，尝试降级方案`)
        try {
          // 尝试权限降级（仅限特定API）
          if (params.deviceId && params.startTime && params.endTime) {
            return await this.handleAuthFallback(apiName, params.deviceId, params.startTime, params.endTime, params.options)
          }
        } catch (fallbackError) {
          console.error(`【权限降级】降级方案也失败:`, fallbackError.message)
        }
      }

      // 如果还有重试次数且不是致命错误
      if (retryCount < this.maxRetries && this.shouldRetry(error)) {
        this.stats.retries++
        console.log(`【请求重试】${apiName} - 第${retryCount + 1}次重试，${this.retryDelay}ms后重试`)

        // 等待重试延迟
        await new Promise(resolve => setTimeout(resolve, this.retryDelay))

        // 递归重试，增加超时时间
        this.requestTimeout = Math.min(this.requestTimeout * 1.5, 120000) // 最大2分钟
        return this.executeWithRetry(apiFunction, params, apiName, retryCount + 1)
      }

      // 重试次数用完或致命错误，抛出异常
      throw error
    }
  }

  // 判断是否应该重试
  shouldRetry(error) {
    const retryableErrors = [
      '请求超时',
      'timeout',
      'Network Error',
      'ERR_NETWORK',
      'ERR_INTERNET_DISCONNECTED'
    ]

    return retryableErrors.some(errorType =>
      error.message.includes(errorType) ||
      error.code === errorType ||
      error.name === errorType
    )
  }

  // 判断是否为权限错误
  isAuthError(error) {
    return error.response && (error.response.status === 401 || error.response.status === 403)
  }

  // 权限降级处理
  async handleAuthFallback(apiName, deviceId, startTime, endTime, options) {
    console.log('【权限降级】尝试使用无权限版本API:', apiName)

    if (apiName.includes('getWaveformDataByrangeTime') && startTime && endTime) {
      // 对于时间范围查询，使用无权限版本
      return await getWaveformDataNoAuth(deviceId, startTime, endTime, options)
    }

    throw new Error('无权限且无可用的降级方案')
  }

  // 清除缓存
  clearCache(pattern = null) {
    if (pattern) {
      for (const [key] of this.cache) {
        if (key.includes(pattern)) {
          this.cache.delete(key)
        }
      }
    } else {
      this.cache.clear()
    }
    console.log('【数据缓存】清除缓存:', pattern || '全部')
  }

  // 批量请求处理
  async batchRequest(requests) {
    const results = await Promise.allSettled(
      requests.map(({ apiName, apiFunction, params }) =>
        this.request(apiName, apiFunction, params)
      )
    )

    return results.map((result, index) => ({
      name: requests[index].apiName,
      success: result.status === 'fulfilled',
      data: result.status === 'fulfilled' ? result.value : null,
      error: result.status === 'rejected' ? result.reason : null
    }))
  }

  // 获取性能统计
  getStats() {
    const avgRequestTime = this.stats.requestTimes.length > 0
      ? this.stats.requestTimes.reduce((a, b) => a + b, 0) / this.stats.requestTimes.length
      : 0

    return {
      totalRequests: this.stats.totalRequests,
      cacheHits: this.stats.cacheHits,
      duplicateRequests: this.stats.duplicateRequests,
      cacheHitRate: this.stats.totalRequests > 0 ? (this.stats.cacheHits / this.stats.totalRequests * 100).toFixed(2) + '%' : '0%',
      duplicateRate: this.stats.totalRequests > 0 ? (this.stats.duplicateRequests / this.stats.totalRequests * 100).toFixed(2) + '%' : '0%',
      avgRequestTime: avgRequestTime.toFixed(2) + 'ms',
      cacheSize: this.cache.size
    }
  }

  // 重置统计
  resetStats() {
    this.stats = {
      totalRequests: 0,
      cacheHits: 0,
      duplicateRequests: 0,
      requestTimes: []
    }
  }
}

export default {
  name: 'WaveformHistory',
  components: {
    FlatDatePicker
  },
  data() {
    return {
      dateRange: [new Date(), new Date()],
      mainChart: null,
      FirstTimeLoad: true, // 标记是否为首次加载
      loadingHistoricalData: false, // 是否正在加载历史数据
      loadingCompleteHistory: true, // 是否正在加载完整历史数据
      loadingProgress: 0, // 加载进度（百分比）
      highlightDialogVisible: false, // 控制高亮分析对话框的显示
      highlightChartInstance: null, // 高亮分析图表实例

      // 数据请求管理器
      dataRequestManager: new DataRequestManager(),

      // 大数据量设备列表（已知数据量较大的设备）
      largeDataDevices: ['20031108'], // 可以根据实际情况添加更多设备ID

      // 自适应加载配置 - 根据API文档优化
      adaptiveLoadingConfig: {
        // 小数据量：使用文档推荐的默认值
        small: { maxPoints: 3000 },
        // 中等数据量：适中的数据点
        medium: { maxPoints: 2000 },
        // 大数据量：较少的数据点
        large: { maxPoints: 1000 },
        // 超大数据量：最少的数据点
        xlarge: { maxPoints: 500 }
      },
      deviceInfo: {
        id: null,
        name: '',
        number: '',
        brand: '',
        model: '',
        type: '',
        actions: 0,
        status: 'normal',
        workRate: 0,
        rank: '',
        planHours: 0,
        runHours: 0,
        // nextMaintenance: 15, // Removed as part of unused maintenance panel
        // healthRate: 85 // Removed as part of unused maintenance panel
      },
      // maintenanceAlerts: [ // Removed as part of unused maintenance panel
      //   { message: '轴承振动值超过预警阈值，建议检查' },
      //   { message: '设备运行时间已超过300小时，建议例行保养' }
      // ],
      waveformInfo: {
        part: '',
        time: '',
        note: ''
      },
      // waveformData: [], // Removed as it seems redundant with xData, yData, zData
      xAxisData: [],    // 记录时间轴数据
      // 存储三轴数据
      xData: [],  // X轴数据
      yData: [],  // Y轴数据
      zData: [],  // Z轴数据
      // referenceData: [], // Removed as unused
      extraData: {},
      dataType: 'rms', // 默认显示rms数据
      // displayMode: 'combined', // Removed as fixed and not used in logic
      // loading: false, // Removed as loadingHistoricalData is used
      noDataAvailable: false,
      timestamps: [],   // 存储时间戳数据

      // 实时模式相关
      realtimeMode: false, // 是否启用实时模式
      isRealtimeActive: false, // 实时图表是否激活
      realtimeManager: null, // 实时数据管理器
      realtimeTimeData: [], // 实时时间轴数据
      realtimeXData: [], // 实时X轴数据
      realtimeYData: [], // 实时Y轴数据
      realtimeZData: [], // 实时Z轴数据
      realtimeWindowSize: 60, // 实时窗口大小（秒）
      pickerOptions: {
        shortcuts: [{
          text: '全部历史数据',
          onClick(picker) {
            const end = new Date();
            const start = new Date('2023-01-01');
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近一周',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近一个月',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近三个月',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
            picker.$emit('pick', [start, end]);
          }
        }]
      },
      // 修改阈值相关数据
      thresholds: {
        x: {
          value: 0.5, // RMS阈值
          peakValue: 1.0, // 峰值阈值
          color: '#F56C6C'
        },
        y: {
          value: 0.5, // RMS阈值
          peakValue: 1.0, // 峰值阈值
          color: '#E6A23C'
        },
        z: {
          value: 0.5, // RMS阈值
          peakValue: 1.0, // 峰值阈值
          color: '#409EFF'
        }
      },
      defaultThresholds: {
        x: { value: 0.5, peakValue: 1.0, color: '#F56C6C' },
        y: { value: 0.5, peakValue: 1.0, color: '#E6A23C' },
        z: { value: 0.5, peakValue: 1.0, color: '#409EFF' }
      },
      thresholdLinesVisible: true,
      thresholdSettingsPanelVisible: true, // 新增：控制阈值设置面板的显示/隐藏
      // selectedSensorId: null, // Removed as currentSensorId and currentPosition are used
      // deviceSensors: [], // Removed as devicePositions and sensorPositionToIdMap are used
      // 添加传感器相关数据属性
      devicePositions: [], // 存储设备安装位置列表
      currentPosition: '', // 当前选中的安装位置
      latheNameToDeviceMap: {}, // latheName到deviceId的映射
      sensorPositionToIdMap: {}, // 传感器位置到传感器ID的映射
      currentSensorId: null, // 当前选中的传感器ID,
      isFullscreen: false, // 是否处于全屏模式
      zoomStep: 10, // 缩放步长百分比
      moveStep: 5, // 移动步长百分比
      keyboardControlEnabled: false, // 键盘控制是否已启用
      savedZoomState: null, // 保存的缩放状态，用于双击重置
      thresholdsDisplayKey: Date.now() // 新增：用于强制刷新阈值设置面板的tabs
    }
  },
  computed: {
    ...mapGetters('websocket', ['connectionInfo']),

    deviceId() {
      return this.$route.query.deviceId ? parseInt(this.$route.query.deviceId) : null
    },

    // WebSocket连接状态
    isWebSocketConnected() {
      return this.connectionInfo.isConnected
    },

    // 当前显示的数据（历史或实时）
    currentDisplayData() {
      if (this.realtimeMode && this.isRealtimeActive) {
        return {
          timeData: this.realtimeTimeData,
          xData: this.realtimeXData,
          yData: this.realtimeYData,
          zData: this.realtimeZData
        }
      } else {
        return {
          timeData: this.xAxisData,
          xData: this.xData,
          yData: this.yData,
          zData: this.zData
        }
      }
    },
    progressPercentage() {
      const planHours = this.parseNumericValue(this.deviceInfo.planHours, 24);
      const runHours = this.parseNumericValue(this.deviceInfo.runHours, 0);

      if (!planHours || planHours <= 0) return 0;

      const percentage = Math.round((runHours / planHours) * 100);
      return Math.max(0, Math.min(100, percentage)); // 限制在0-100之间
    },
    waveformTitle() {
      const typeMap = {rms: '均方根(RMS)', peak: '峰值(Peak)'}
      // const sensorName = this.getCurrentSensorName() // Removed as sensorName is not used
      // 修改返回标题，显示传感器位置
      return `设备振动历史 - ${this.currentPosition ? '位置: ' + this.currentPosition + ' - ' : ''}三轴${typeMap[this.dataType] || '均方根(RMS)'}`
    },
    // 新增：用于显示在阈值面板的有效设备类型
    effectiveDeviceTypeForThresholds() {
      if (this.deviceInfo && (this.deviceInfo.id || this.deviceInfo.name)) {
        const type = this._getEffectiveDeviceType();
        if (type === 'default') {
          // deviceInfo.type 本身可能是 '未知类型', 'default', 空，或者名称也无法解析
          // _getEffectiveDeviceType 会在这种情况下返回 'default'
          return this.deviceInfo.type && this.deviceInfo.type !== '未知类型' && this.deviceInfo.type !== 'default' ? this.deviceInfo.type : '系统预设';
        }
        return type; // "磨床" 或原始有效的 deviceInfo.type
      }
      return '未知类型'; // 初始或设备信息不完整时
    }
    // Removed healthStatusColor and healthStatusText as they were related to the unused maintenance panel
  },
  created() {
    // 根据deviceId获取设备信息
    if (this.deviceId) {
      this.performInitialLoad(this.deviceId)
    }
  },
  watch: {
    // 监听路由参数变化，当deviceId变化时重新加载数据
    '$route.query.deviceId': function (newDeviceId) {
      if (newDeviceId && parseInt(newDeviceId) !== this.deviceInfo.id) {
        // 重置数据
        this.resetData()
        // 加载新设备数据，使用loadingHistoricalData代替全局loading
        this.loadingHistoricalData = true
        this.performInitialLoad(parseInt(newDeviceId))
          .finally(() => {
            this.loadingHistoricalData = false
          })
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initMainChart()
      // 监听窗口大小变化，重新调整图表大小
      window.addEventListener('resize', this.resizeChart)

      // 监听全屏状态变化事件
      document.addEventListener('fullscreenchange', this.handleFullscreenChange)
      document.addEventListener('webkitfullscreenchange', this.handleFullscreenChange)
      document.addEventListener('mozfullscreenchange', this.handleFullscreenChange)
      document.addEventListener('MSFullscreenChange', this.handleFullscreenChange)
    })
  },
  beforeDestroy() {
    // 移除事件监听器
    window.removeEventListener('resize', this.resizeChart)
    document.removeEventListener('fullscreenchange', this.handleFullscreenChange)
    document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange)
    document.removeEventListener('mozfullscreenchange', this.handleFullscreenChange)
    document.removeEventListener('MSFullscreenChange', this.handleFullscreenChange)

    // 移除键盘事件监听器
    this.disableKeyboardControl()

    // 如果处于全屏状态，退出全屏
    if (this.isFullscreen) {
      this.exitFullscreen()
    }

    // 销毁图表实例
    if (this.mainChart) this.mainChart.dispose()

    // 清理数据请求管理器缓存
    if (this.dataRequestManager) {
      this.dataRequestManager.clearCache()
      console.log('【组件销毁】清理数据请求管理器缓存')
    }
  },
  methods: {
    // ==================== 实时模式相关方法 ====================
    // 确保 getDeviceTimeRangeData 方法如下所示
    async getDeviceTimeRangeData(deviceId) {
      try {
        const response = await this.dataRequestManager.request(
          'getDeviceTimeRange',
          () => getDeviceTimeRange(deviceId),
          { deviceId }
        );

        if (response.code === 200 && response.data && Array.isArray(response.data) && response.data.length === 2) {
          const [startTime, endTime] = response.data;
          return {
            startTime: this.formatTimeForApi(new Date(startTime)),
            endTime: this.formatTimeForApi(new Date(endTime)),
            startDate: new Date(startTime),
            endDate: new Date(endTime)
          };
        } else {
          throw new Error('时间范围数据格式不正确');
        }
      } catch (error) {
        console.error('获取设备时间范围失败:', error);
        this.$message.error('获取设备时间范围失败: ' + error.message);
        // 提供默认时间范围作为降级方案
        const now = new Date();
        const oneYearAgo = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);
        return {
          startTime: this.formatTimeForApi(oneYearAgo),
          endTime: this.formatTimeForApi(now),
          startDate: oneYearAgo,
          endDate: now
        };
      }
    },

    /**
     * 处理实时模式切换
     */
    handleRealtimeModeChange(enabled) {
      this.realtimeMode = enabled

      if (enabled) {
        if (!this.isWebSocketConnected) {
          this.$message.warning('WebSocket未连接，无法启用实时模式')
          this.realtimeMode = false
          return
        }
        this.initRealtimeMode()
      } else {
        this.stopRealtimeMode()
      }
    },

    /**
     * 初始化实时模式
     */
    async initRealtimeMode() {
      try {
        // 创建实时数据管理器
        this.realtimeManager = new RealtimeWaveformManager({
          windowSize: this.realtimeWindowSize,
          maxDataPoints: 1000,
          updateInterval: 100
        })

        // 监听数据更新事件
        this.realtimeManager.on('dataUpdated', this.handleRealtimeDataUpdate)

        // 设置WebSocket数据监听
        this.setupRealtimeDataListener()

        this.$message.success('实时模式已初始化')
      } catch (error) {
        console.error('初始化实时模式失败:', error)
        this.$message.error('初始化实时模式失败')
      }
    },

    /**
     * 停止实时模式
     */
    stopRealtimeMode() {
      if (this.realtimeManager) {
        this.realtimeManager.destroy()
        this.realtimeManager = null
      }

      this.isRealtimeActive = false
      this.clearRealtimeData()

      // 切换回历史数据显示
      this.updateChartData()

      this.$message.info('已退出实时模式')
    },

    /**
     * 设置实时数据监听
     */
    setupRealtimeDataListener() {
      // 监听WebSocket设备信息更新
      this.$store.watch(
        (state) => state.websocket.deviceInfo,
        (newDeviceInfo) => {
          if (this.realtimeMode && this.isRealtimeActive && this.realtimeManager) {
            this.processWebSocketData(newDeviceInfo)
          }
        },
        { deep: true }
      )
    },

    /**
     * 处理WebSocket数据
     */
    processWebSocketData(deviceInfoList) {
      if (!Array.isArray(deviceInfoList)) return

      // 找到当前设备的数据
      const deviceData = deviceInfoList.find(item =>
        item.deviceId === this.deviceId.toString() ||
        item.deviceId === this.deviceId
      )

      if (!deviceData) return

      // 如果指定了传感器位置，进行过滤
      if (this.currentPosition && deviceData.position !== this.currentPosition) {
        return
      }

      // 添加数据到管理器
      this.realtimeManager.addDataPoint({
        timestamp: deviceData.timestamp || Date.now(),
        xRms: deviceData.xRms || 0,
        yRms: deviceData.yRms || 0,
        zRms: deviceData.zRms || 0
      })
    },

    /**
     * 处理实时数据更新
     */
    handleRealtimeDataUpdate(updateData) {
      const { timeData, seriesData } = updateData

      // 更新实时数据
      this.realtimeTimeData = timeData
      this.realtimeXData = seriesData.xRms || []
      this.realtimeYData = seriesData.yRms || []
      this.realtimeZData = seriesData.zRms || []

      // 更新图表
      this.updateRealtimeChart()
    },

    /**
     * 更新实时图表
     */
    updateRealtimeChart() {
      if (!this.mainChart || !this.realtimeMode) return

      // 格式化时间数据
      const formattedTimeData = this.realtimeTimeData.map(time => {
        return new Date(time).toLocaleTimeString()
      })

      // 更新图表数据
      this.mainChart.setOption({
        xAxis: {
          data: formattedTimeData
        },
        series: [
          { data: this.realtimeXData },
          { data: this.realtimeYData },
          { data: this.realtimeZData }
        ]
      }, false)

      // 自动滚动到最新数据
      if (formattedTimeData.length > 50) {
        const dataLength = formattedTimeData.length
        const start = Math.max(0, ((dataLength - 50) / dataLength) * 100)

        this.mainChart.setOption({
          dataZoom: [{
            start: start,
            end: 100
          }]
        }, false)
      }
    },

    /**
     * 切换实时图表状态
     */
    async toggleRealtimeChart() {
      if (!this.realtimeManager) {
        this.$message.error('实时管理器未初始化')
        return
      }

      this.isRealtimeActive = !this.isRealtimeActive

      if (this.isRealtimeActive) {
        // 启动实时模式前先加载一些历史数据作为基础
        await this.loadRealtimeHistoricalData()

        this.realtimeManager.start()
        this.$message.success('实时图表已启动')
      } else {
        this.realtimeManager.stop()
        this.$message.info('实时图表已暂停')
      }
    },

    /**
     * 加载实时模式的历史数据
     */
    async loadRealtimeHistoricalData() {
      try {
        const endTime = new Date()
        const startTime = new Date(endTime.getTime() - this.realtimeWindowSize * 1000)

        // 这里可以调用API获取历史数据
        // 暂时使用模拟数据
        const historicalData = this.generateMockRealtimeData(startTime, endTime)

        // 清空现有实时数据
        this.clearRealtimeData()

        // 添加历史数据到管理器
        historicalData.forEach(point => {
          this.realtimeManager.addDataPoint(point)
        })

      } catch (error) {
        console.error('加载实时历史数据失败:', error)
      }
    },

    /**
     * 生成模拟实时数据
     */
    generateMockRealtimeData(startTime, endTime) {
      const data = []
      const interval = 1000 // 1秒间隔

      for (let time = startTime.getTime(); time <= endTime.getTime(); time += interval) {
        data.push({
          timestamp: time,
          xRms: Math.random() * 2 + Math.sin(time / 10000) * 0.5,
          yRms: Math.random() * 2 + Math.cos(time / 8000) * 0.5,
          zRms: Math.random() * 2 + Math.sin(time / 12000) * 0.5
        })
      }

      return data
    },

    /**
     * 清空实时数据
     */
    clearRealtimeData() {
      this.realtimeTimeData = []
      this.realtimeXData = []
      this.realtimeYData = []
      this.realtimeZData = []

      if (this.realtimeManager) {
        this.realtimeManager.clear()
      }

      this.$message.success('实时数据已清空')
    },

    // ==================== 原有方法 ====================

    // 新增：内部辅助方法，用于确定有效的设备类型
    _getEffectiveDeviceType() {
      let typeToUse = null;

      // 优先级 1: 使用 deviceInfo.type (来自后端设备信息)
      if (this.deviceInfo && this.deviceInfo.type &&
          this.deviceInfo.type !== '未知类型' &&
          this.deviceInfo.type !== 'default' &&
          this.deviceInfo.type.trim() !== '') {
        typeToUse = this.deviceInfo.type.trim();
        console.log('【阈值类型决策】使用 deviceInfo.type:', typeToUse);
      }

      // 优先级 2: 如果上述类型无效，尝试从设备名称派生
      if (!typeToUse && this.deviceInfo && this.deviceInfo.name) {
        const derivedType = this.getDeviceTypeFromName(this.deviceInfo.name);
        if (derivedType && derivedType !== 'default' && derivedType.trim() !== '') {
          typeToUse = derivedType.trim();
          console.log('【阈值类型决策】使用从名称派生的类型:', typeToUse);
        }
      }

      const finalType = typeToUse || 'default';
      console.log('【阈值类型决策】最终使用的类型:', finalType);
      return finalType;
    },

    // 优化的初始加载方法，使用数据请求管理器并行获取数据
    // 修改 performInitialLoad 方法中的波形数据加载部分
    async performInitialLoad(deviceId) {
      console.log('【优化加载V2】开始执行优化的并行数据加载，deviceId:', deviceId);

      // 重置加载状态
      this.loadingHistoricalData = false;
      this.loadingProgress = 0;

      try {
        // 使用批量请求管理器并行获取基础数据
        const batchRequests = [
          {
            apiName: 'getDevice',
            apiFunction: () => getDevice(deviceId),
            params: { deviceId }
          },
          {
            apiName: 'getAccelerationData',
            apiFunction: () => getAccelerationData(),
            params: {}
          }
        ];

        console.log('【优化加载V2】发起批量请求');
        const results = await this.dataRequestManager.batchRequest(batchRequests);

        const deviceInfoResult = results.find(r => r.name === 'getDevice');
        const accelerationDataResult = results.find(r => r.name === 'getAccelerationData');

        console.log('【优化加载V2】批量请求完成', {
          deviceInfo: deviceInfoResult.success,
          accelerationData: accelerationDataResult.success
        });

        // 处理设备信息
        if (deviceInfoResult.success && deviceInfoResult.data && deviceInfoResult.data.code === 200) {
          const device = deviceInfoResult.data.data;
          // 映射后端设备数据到前端展示格式
          this.deviceInfo = {
            id: device.deviceNumber,
            name: device.deviceName || '未知设备',
            number: device.deviceNumber || '无编号',
            brand: device.manufacturer || '未知品牌',
            model: device.specifications || '未知型号',
            type: device.deviceType || '未知类型',
            actions: device.actions || 0,
            status: device.status || '未知状态',
            workRate: this.parseWorkRate(device.workRate),
            rank: device.rank || '未知排名',
            planHours: this.parseNumericValue(device.planHours, 24),
            runHours: this.parseNumericValue(device.runHours, 0)
          };

          // 在获取设备信息后，异步加载设备类型特定的阈值（不阻塞主流程）
          this.loadDeviceThresholdsAsync();

          // 检查传感器数据并处理
          if (accelerationDataResult.success && accelerationDataResult.data && accelerationDataResult.data.code === 200) {
            console.log('【优化加载V2】开始处理传感器数据');
            this.processSensorData(accelerationDataResult.data.data, this.deviceInfo.name);
          } else {
            console.warn('【优化加载V2】传感器数据获取失败或无数据');
            this.resetSensorData();
          }
        } else {
          console.error('【优化加载V2】设备信息获取失败');
          this.$message.error('获取设备信息失败');
        }

        // 获取波形数据（异步进行，不阻塞UI）
        console.log('【优化加载V2】开始获取波形数据，currentSensorId:', this.currentSensorId);
        this.loadWaveformDataAsync(deviceId);

      } catch (error) {
        console.error('【优化加载V2】数据加载过程中发生错误', error);
        this.$message.error('加载数据失败，请刷新页面');
      }
    },

    // 新增：处理传感器数据的独立方法
    processSensorData(sensorDataList, deviceName) {
      console.log('【数据处理】开始处理传感器数据');

      // 初始化映射
      this.latheNameToDeviceMap = {};
      this.sensorPositionToIdMap = {};

      // 按latheName分组处理设备数据
      sensorDataList.forEach(deviceData => {
        if (deviceData.latheName) {
          if (!this.latheNameToDeviceMap[deviceData.latheName]) {
            this.latheNameToDeviceMap[deviceData.latheName] = [];
          }
          if (!this.latheNameToDeviceMap[deviceData.latheName].includes(deviceData.deviceId)) {
            this.latheNameToDeviceMap[deviceData.latheName].push(deviceData.deviceId);
          }
        }
      });

      // 根据当前设备名称过滤出相关数据
      const sameLatheDevices = sensorDataList.filter(item => item.latheName === deviceName);

      if (sameLatheDevices.length > 0) {
        // 提取安装位置信息(传感器)和对应的ID
        const positions = new Set();
        sameLatheDevices.forEach(item => {
          if (item.putPlace && typeof item.putPlace === 'string') {
            positions.add(item.putPlace);

            // 保存传感器位置与ID的映射关系
            const sensorId = item.sensorId || item.deviceId;
            if (sensorId) {
              this.sensorPositionToIdMap[item.putPlace] = sensorId;
              console.log(`【数据处理】映射传感器位置 ${item.putPlace} 的ID:`, sensorId);
            }
          }
        });

        // 转为数组
        this.devicePositions = Array.from(positions);
        console.log(`【数据处理】获取到设备 ${deviceName} 的传感器列表:`, this.devicePositions);

        // 默认选中第一个传感器
        if (this.devicePositions.length > 0 && !this.currentPosition) {
          this.currentPosition = this.devicePositions[0];
          this.currentSensorId = this.sensorPositionToIdMap[this.currentPosition];
          console.log('【数据处理】默认选中传感器:', this.currentPosition, '传感器ID:', this.currentSensorId);
        }
      } else {
        console.warn(`【数据处理】未找到与设备 ${deviceName} 匹配的传感器数据`);
        this.resetSensorData();
      }
    },

    // 新增：重置传感器数据
    resetSensorData() {
      this.devicePositions = [];
      this.currentPosition = '';
      this.currentSensorId = null;
      this.latheNameToDeviceMap = {};
      this.sensorPositionToIdMap = {};
    },

    // 新增：异步加载设备阈值（不阻塞主流程）
    async loadDeviceThresholdsAsync() {
      try {
        await this.loadDeviceThresholds();
      } catch (error) {
        console.error('【异步阈值加载】失败:', error);
        // 不显示错误消息，避免干扰用户体验
      }
    },

    // 修改 loadWaveformDataAsync 方法
    async loadWaveformDataAsync(deviceId) {
      try {
        this.loadingHistoricalData = true;
        this.loadingProgress = 10;

        // 显示加载提示
        this.$message.info('正在加载数据，请稍候...');

        if (this.currentSensorId) {
          // 直接使用优化的方法获取完整历史数据
          await this.fetchAllHistoricalDataOptimized(this.currentSensorId);
        } else {
          // 对于没有传感器ID的情况，仍然使用分步加载策略
          await this.loadLargeDatasetWithSteps(deviceId);
        }
      } catch (error) {
        console.error('【异步波形加载】失败:', error);

        // 根据错误类型给出不同的提示
        if (error.message.includes('超时')) {
          this.$message.error('数据加载超时，请尝试选择较小的时间范围或刷新页面');
        } else {
          this.$message.error('波形数据加载失败，请检查网络连接或联系管理员');
        }
      } finally {
        this.loadingHistoricalData = false;
        this.loadingProgress = 0;
      }
    },

    // 新增：大数据集分步加载
    // 修改 loadLargeDatasetWithSteps 方法
    // 新增：使用时间范围加载更多数据步骤
    async loadMoreDataStepWithTimeRange(deviceId, timeRange) {
      try {
        this.loadingProgress = 60;

        const moreOptions = this.getAdaptiveLoadingConfig(deviceId, 'more');

        const moreDataResponse = await this.dataRequestManager.request(
          'getWaveformDataByrangeTime_more',
          () => getWaveformDataByrangeTime(deviceId, timeRange.startTime, timeRange.endTime, null, moreOptions),
          { deviceId, startTime: timeRange.startTime, endTime: timeRange.endTime, step: 'more' }
        );

        if (moreDataResponse.code === 200 && moreDataResponse.data) {
          this.processWaveformResponse(moreDataResponse);
          this.loadingProgress = 80;

          // 显示成功消息
          this.$message.success('数据加载完成');
        }

      } catch (error) {
        console.warn('【分步加载】加载更多数据失败，保持基础数据:', error.message);
        this.$message.warning('部分数据加载失败，已显示可用数据');
      }
    },
    async loadLargeDatasetWithSteps(deviceId) {
      console.log('【分步加载】开始分步加载大数据集:', deviceId);

      try {
        // 直接使用新接口获取时间范围
        const timeRange = await this.getDeviceTimeRangeData(deviceId);

        // 设置日期范围显示
        this.dateRange = [timeRange.startDate, timeRange.endDate];
        this.loadingProgress = 20;
        console.log('【分步加载】获取到时间范围:', timeRange.startTime, '到', timeRange.endTime);

        // 使用获取到的时间范围直接请求完整历史数据
        const basicOptions = this.getAdaptiveLoadingConfig(deviceId, 'basic');

        const basicResponse = await this.dataRequestManager.request(
          'getWaveformDataByrangeTime_basic',
          () => getWaveformDataByrangeTime(deviceId, timeRange.startTime, timeRange.endTime, null, basicOptions),
          { deviceId, startTime: timeRange.startTime, endTime: timeRange.endTime, step: 'basic' }
        );

        if (basicResponse.code === 200 && basicResponse.data) {
          // 立即显示基本数据
          this.processWaveformResponse(basicResponse);
          this.loadingProgress = 40;

          // 获取更多数据
          console.log('【分步加载】获取更多数据');
          await this.loadMoreDataStepWithTimeRange(deviceId, timeRange);
        } else {
          throw new Error('无法获取基本数据');
        }

      } catch (error) {
        console.error('【分步加载】失败:', error);

        // 如果分步加载也失败，尝试最后的降级方案
        console.log('【分步加载】尝试最终降级方案');
        await this.fetchWaveformDataWithFallback(deviceId, this.currentSensorId);
      }
    },

    // 新增：加载更多数据步骤
    async loadMoreDataStep(deviceId) {
      try {
        this.loadingProgress = 60;

        const moreOptions = this.getAdaptiveLoadingConfig(deviceId, 'more');

        const moreDataResponse = await this.dataRequestManager.request(
          'getDeviceWaveforms_more',
          () => getDeviceWaveforms(deviceId, this.currentSensorId, moreOptions),
          { deviceId, sensorId: this.currentSensorId, step: 'more' }
        );

        if (moreDataResponse.code === 200 && moreDataResponse.data) {
          this.processWaveformResponse(moreDataResponse);
          this.loadingProgress = 80;

          // 显示成功消息
          this.$message.success('数据加载完成');
        }

      } catch (error) {
        console.warn('【分步加载】第2步失败，保持第1步数据:', error.message);
        this.$message.warning('部分数据加载失败，已显示可用数据');
      }
    },

    toggleThresholdSettingsPanel() {
      this.thresholdSettingsPanelVisible = !this.thresholdSettingsPanelVisible;
    },
    // 根据设备类型返回对应的形状类名
    getDeviceShape(deviceType) {
      if (!deviceType) {
        console.warn('设备类型为空，使用默认图标');
        return 'default';
      }

      // 设备类型映射表
      const shapeMap = {
        // 车床类
        '车床': 'lathe',
        '数控车床': 'lathe',
        '立式车床': 'lathe',
        '卧式车床': 'lathe',
        'CNC车床': 'lathe',
        '普通车床': 'lathe',

        // 铣床类
        '铣床': 'mill',
        '数控铣床': 'mill',
        '立式铣床': 'mill',
        '卧式铣床': 'mill',
        'CNC铣床': 'mill',
        '普通铣床': 'mill',
        '加工中心': 'mill',

        // 钻床类
        '钻床': 'drill',
        '钻铣床': 'drill',
        '攻丝机': 'drill',
        '立式钻床': 'drill',
        '卧式钻床': 'drill',
        '摇臂钻床': 'drill',
        '台式钻床': 'drill',

        // 磨床类
        '磨床': 'grinder',
        '内圆磨床': 'grinder',
        '外圆磨床': 'grinder',
        '平面磨床': 'grinder',
        '无心磨床': 'grinder',
        '工具磨床': 'grinder',
        '曲轴磨床': 'grinder',

        // 机器人类
        '机器人': 'robot',
        '工业机器人': 'robot',
        '协作机器人': 'robot',
        '装配机器人': 'robot',
        '焊接机器人': 'robot',
        '搬运机器人': 'robot',
        'AGV': 'robot',

        // 压力机类
        '压力机': 'press',
        '冲床': 'press',
        '锻压机': 'press',
        '液压机': 'press',
        '机械压力机': 'press',
        '伺服压力机': 'press',
        '冲压机': 'press',

        // 其他通用设备
        '注塑机': 'injection',
        '压铸机': 'casting',
        '锯床': 'saw',
        '剪板机': 'shear',
        '折弯机': 'bender',
        '清洗机': 'washer',
        '包装机': 'packer'
      };

      // 获取设备类型，如果未找到则返回默认类型并记录日志
      const deviceShape = shapeMap[deviceType];
      if (!deviceShape) {
        console.warn(`未知设备类型: ${deviceType}，使用默认图标`);
      }
      return deviceShape || 'default';
    },

    // 获取设备形状的SVG路径
    getDeviceShapePath(deviceType) {
      // 简化的SVG路径，代表不同设备的特征
      const pathMap = {
        // 车床 - 水平方向的工件和刀具
        'lathe': 'M20,40 H80 M30,30 V60 M70,50 H30',

        // 铣床 - 垂直方向的刀具和工作台
        'mill': 'M50,20 V40 M30,60 H70 M40,50 V70 M60,50 V70',

        // 钻床 - 钻头和工作台
        'drill': 'M50,20 V70 M30,50 H70 M45,25 L55,35 M45,35 L55,25',

        // 磨床 - 砂轮和工件
        'grinder': 'M30,50 H70 M50,30 V70 M65,50 A15,15 0 1,0 35,50 A15,15 0 1,0 65,50',

        // 机器人 - 机械臂
        'robot': 'M50,30 V50 M50,50 L30,70 M50,50 L70,70 M40,30 H60',

        // 压力机 - 上下压力结构
        'press': 'M30,30 H70 M50,30 V40 M30,60 H70 M30,40 V60 M70,40 V60',

        // 注塑机 - 注塑机轮廓
        'injection': 'M30,30 H70 V70 H30 V30 M40,40 H60 V60 M50,30 V70',

        // 压铸机 - 压铸机轮廓
        'casting': 'M30,30 H70 V70 H30 V30 M40,35 H60 M40,45 H60 M40,55 H60',

        // 锯床 - 锯条和工作台
        'saw': 'M30,50 H70 M45,30 L55,70 M35,40 L65,60',

        // 剪板机 - 剪切刀具
        'shear': 'M30,30 H70 M30,50 H70 M40,30 L60,50 M40,50 L60,30',

        // 折弯机 - 折弯结构
        'bender': 'M30,30 H70 M30,50 H70 M50,30 L30,70 M50,30 L70,70',

        // 清洗机 - 清洗槽
        'washer': 'M30,30 H70 V70 H30 V30 M35,40 H65 V60 H35 V40',

        // 包装机 - 包装轮廓
        'packer': 'M30,30 H70 V70 H30 V30 M40,40 H60 V60 H40 V40 M45,45 H55 V55 H45 V45',

        // 默认 - 简单的机器轮廓
        'default': 'M30,30 H70 V70 H30 V30 M40,40 H60 V60 H40 V40'
      };

      return pathMap[this.getDeviceShape(deviceType)] || pathMap['default'];
    },
    formatRunHours(hours) {
      if (hours == null || isNaN(hours)) {
        return '未知';
      }
      const h = Math.floor(hours);
      const m = Math.round((hours % 1) * 60);
      return `${h} 小时 ${m} 分钟`;
    },

    /**
     * 解析工作率，确保返回数字类型
     */
    parseWorkRate(workRate) {
      // 如果是数字，直接返回
      if (typeof workRate === 'number' && !isNaN(workRate)) {
        return Math.max(0, Math.min(100, workRate)); // 限制在0-100之间
      }

      // 如果是字符串，尝试解析
      if (typeof workRate === 'string') {
        // 移除百分号和其他非数字字符，尝试解析
        const numericValue = parseFloat(workRate.replace(/[^\d.]/g, ''));
        if (!isNaN(numericValue)) {
          return Math.max(0, Math.min(100, numericValue));
        }
      }

      // 如果无法解析，返回0
      return 0;
    },

    /**
     * 解析数值，确保返回数字类型
     */
    parseNumericValue(value, defaultValue = 0) {
      // 如果是数字，直接返回
      if (typeof value === 'number' && !isNaN(value)) {
        return value;
      }

      // 如果是字符串，尝试解析
      if (typeof value === 'string') {
        const numericValue = parseFloat(value);
        if (!isNaN(numericValue)) {
          return numericValue;
        }
      }

      // 如果无法解析，返回默认值
      return defaultValue;
    },
    toIndex() {
      this.$router.push('/index')
    },
    resizeChart() {
      if (this.mainChart) this.mainChart.resize()
    },
    // 重置数据方法 - 优化版
    resetData() {
      console.log('【优化加载】重置所有数据');

      // 重置加载状态
      this.loadingHistoricalData = false;
      this.loadingProgress = 0;

      // 重置设备信息
      this.deviceInfo = {
        id: null,  // 重要：确保设置为null，这样watch才会正确触发
        name: '',
        number: '',
        brand: '',
        model: '',
        type: '',
        actions: 0,
        status: 'normal',
        workRate: 0,
        rank: '',
        planHours: 0,
        runHours: 0
      }

      // 重置波形信息
      this.waveformInfo = {
        part: '',
        time: '',
        note: ''
      }

      // 重置图表数据
      this.xAxisData = []
      this.xData = []
      this.yData = []
      this.zData = []
      this.extraData = {}
      this.timestamps = []
      this.noDataAvailable = false

      // 重置传感器相关数据
      this.devicePositions = []
      this.currentPosition = ''
      this.currentSensorId = null
      this.latheNameToDeviceMap = {}
      this.sensorPositionToIdMap = {}

      // 重置日期范围
      const today = new Date()
      this.dateRange = [today, today]

      // 如果图表已初始化，清空图表数据
      if (this.mainChart) {
        this.mainChart.setOption({
          xAxis: {data: []},
          series: [{data: []}, {data: []}, {data: []}]
        })
      }

      // 重置阈值相关数据
      this.thresholds = {
        x: {value: 0.5, color: '#67C23A'},
        y: {value: 0.5, color: '#67C23A'},
        z: {value: 0.5, color: '#67C23A'}
      };

      this.updateThresholdLines();

      console.log('【优化加载】数据重置完成');
    },

    // 优化的时间范围变化处理
    async handleDateRangeChange() {
      if (!this.dateRange || this.dateRange.length !== 2) {
        this.$message.warning('请选择有效的时间范围');
        return;
      }

      this.loadingHistoricalData = true;
      this.loadingCompleteHistory = false;
      this.loadingProgress = 10;

      const startTime = this.formatTimeForApi(this.dateRange[0]);
      const endTime = this.formatTimeForApi(this.dateRange[1]);

      try {
        console.log('【优化时间范围】查询时间范围:', startTime, '到', endTime);

        // 使用数据请求管理器获取时间范围数据 - 根据API文档优化
        const response = await this.dataRequestManager.request(
          'getWaveformDataByrangeTime_range',
          () => {
            // 使用智能配置获取合适的 maxPoints
            const options = this.getAdaptiveLoadingConfig(this.deviceId || this.currentSensorId, 'range');

            if (this.currentSensorId) {
              return getWaveformDataByrangeTime(this.currentSensorId, startTime, endTime, null, options);
            } else if (this.deviceId) {
              return getWaveformDataByrangeTime(this.deviceId, startTime, endTime, this.currentSensorId, options);
            } else {
              throw new Error('无效的设备或传感器ID');
            }
          },
          {
            id: this.currentSensorId || this.deviceId,
            startTime,
            endTime,
            type: this.currentSensorId ? 'sensor' : 'device'
          }
        );

        this.loadingProgress = 80;
        await this.handleWaveformResponse(response);
        this.loadingProgress = 100;

      } catch (error) {
        console.error('【优化时间范围】查询失败:', error);
        this.handleWaveformError(error);
      } finally {
        setTimeout(() => {
          this.loadingHistoricalData = false;
          this.loadingProgress = 0;
        }, 300);
      }
    },

    // 获取传感器数据 - 根据API文档优化
    async fetchSensorData(sensorId, startTime, endTime) {
      console.log('【传感器ID跟踪】获取传感器数据:', sensorId, '时间范围:', startTime, '到', endTime);

      // 使用API文档推荐的参数
      const options = {
        maxPoints: 2000  // 时间范围查询的默认值
      };

      return await getWaveformDataByrangeTime(sensorId, startTime, endTime, null, options);
    },

    // 处理波形数据响应
    async handleWaveformResponse(response) {
      if (response.code !== 200 || !response.data) {
        throw new Error('响应数据无效');
      }

      const data = Array.isArray(response.data) ? response.data[0] : response.data;
      if (!data) {
        throw new Error('无数据');
      }

      // 更新数据
      this.extraData = data.extraData || {};
      this.timestamps = data.timestamps || [];
      this.noDataAvailable = false;

      // 更新显示
      await this.updateDisplayData();
      console.log('【传感器ID跟踪】数据更新成功');
    },

    // 处理波形数据错误
    handleWaveformError(error) {
      console.error('【传感器ID跟踪】数据获取失败:', error);

      // 重置数据
                  this.extraData = {};
                  this.timestamps = [];
      this.noDataAvailable = true;

      // 显示错误信息
      const errorMap = {
        '请求超时': '数据加载超时，请重试',
        '无数据': '所选时间范围内无振动历史数据',
        '无效的设备或传感器ID': '请选择有效的设备或传感器',
        '响应数据无效': '数据获取失败，请重试'
      };
      this.$message.error(errorMap[error.message] || '数据获取失败，请重试');
    },

    // 更新阈值数据
    updateThresholds(thresholds = null) {
      const defaultThresholds = {
                    x: {value: 0.5, color: '#67C23A'},
                    y: {value: 0.5, color: '#67C23A'},
                    z: {value: 0.5, color: '#67C23A'}
                  };

      if (!thresholds) {
        this.thresholds = defaultThresholds;
        return;
      }

      this.thresholds = ['x', 'y', 'z'].reduce((acc, axis) => {
        acc[axis] = {
          value: (thresholds[axis]?.value ?? defaultThresholds[axis].value),
          color: (thresholds[axis]?.color ?? defaultThresholds[axis].color)
        };
        return acc;
      }, {});
    },
    // 格式化时间为API所需格式 @author qianz
    formatTimeForApi(date) {
      if (!(date instanceof Date)) {
        date = new Date(date);
      }
      // 增加一个健壮性判断，如果转换后仍然无效，则返回错误提示或当前时间
      if (isNaN(date.getTime())) {
        console.error('Invalid date received in formatTimeForApi:', date);
        // 可以选择返回一个默认值或者抛出错误
        // 例如，返回当前时间的格式化字符串
        const now = new Date();
        const year = now.getFullYear();
        const month = (now.getMonth() + 1).toString().padStart(2, '0');
        const day = now.getDate().toString().padStart(2, '0');
        const hours = now.getHours().toString().padStart(2, '0');
        const minutes = now.getMinutes().toString().padStart(2, '0');
        const seconds = now.getSeconds().toString().padStart(2, '0');
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      }
      const year = date.getFullYear();
      const month = (date.getMonth() + 1).toString().padStart(2, '0');
      const day = date.getDate().toString().padStart(2, '0');
      const hours = date.getHours().toString().padStart(2, '0');
      const minutes = date.getMinutes().toString().padStart(2, '0');
      const seconds = date.getSeconds().toString().padStart(2, '0');

      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },

    // 切换数据类型
    switchDataType(type) {
      this.dataType = type
      this.updateDisplayData()
      // 在数据更新后重新应用阈值可视化
      this.$nextTick(() => {
        this.updateChartVisualization()
      })
    },

    // 根据当前选择更新显示的数据
    updateDisplayData() {
      console.log('更新显示数据开始，extraData:', JSON.stringify(this.extraData).substring(0, 200) + '...');

      // 如果没有extraData，尝试使用已有的轴数据
      if (!this.extraData || Object.keys(this.extraData).length === 0) {
        console.log('没有extraData，查看是否有已有的轴数据');
        console.log('现有轴数据长度:', this.xData.length, this.yData.length, this.zData.length);

        // 如果已有轴数据，直接返回，无需再次处理
        if (this.xData.length > 0 || this.yData.length > 0 || this.zData.length > 0) {
          console.log('使用已有的轴数据');
          this.noDataAvailable = false;
          return;
        }

        this.noDataAvailable = true;
        return;
      }

      // 创建时间轴数据
      if (this.timestamps && this.timestamps.length > 0) {
        console.log('使用timestamps创建X轴数据, 长度:', this.timestamps.length);
        this.xAxisData = this.timestamps.map(timestamp =>
          this.formatDate(timestamp, true)
        );
      }

      // 记录更新前的数据状态
      const beforeUpdate = {
        xDataLength: this.xData.length,
        yDataLength: this.yData.length,
        zDataLength: this.zData.length
      };

      if (this.dataType === 'rms') {
        // 均方根数据
        this.xData = this.extraData.xRmsData || [];
        this.yData = this.extraData.yRmsData || [];
        this.zData = this.extraData.zRmsData || [];
        console.log('RMS数据更新:', this.xData.length, this.yData.length, this.zData.length);
      } else if (this.dataType === 'peak') {
        // 峰值数据
        this.xData = this.extraData.xPeakData || [];
        this.yData = this.extraData.yPeakData || [];
        this.zData = this.extraData.zPeakData || [];
        console.log('Peak数据更新:', this.xData.length, this.yData.length, this.zData.length);
      }

      // 如果所有轴数据都为空，尝试使用备用数据
      if (!this.xData.length && !this.yData.length && !this.zData.length) {
        console.log('所有轴数据为空，尝试使用备用数据');

        // 尝试使用可能存在的其他格式数据
        if (this.extraData.xData && this.extraData.xData.length) {
          this.xData = this.extraData.xData;
          this.yData = this.extraData.yData || [];
          this.zData = this.extraData.zData || [];
          console.log('使用备用数据:', this.xData.length, this.yData.length, this.zData.length);
        }

        // 再次检查数据，支持更多可能的格式
        if (!this.xData.length && !this.yData.length && !this.zData.length) {
          // 尝试所有可能的数据字段名
          const possibleFields = [
            ['x', 'y', 'z'],
            ['X', 'Y', 'Z'],
            ['xAxis', 'yAxis', 'zAxis'],
            ['axis1', 'axis2', 'axis3']
          ];

          for (const [xField, yField, zField] of possibleFields) {
            if (this.extraData[xField] && this.extraData[xField].length) {
              console.log(`尝试使用字段: ${xField}, ${yField}, ${zField}`);
              this.xData = this.extraData[xField] || [];
              this.yData = this.extraData[yField] || [];
              this.zData = this.extraData[zField] || [];
              break;
            }
          }

          console.log('备用字段数据更新:', this.xData.length, this.yData.length, this.zData.length);
        }
      }

      // 放宽数据可用性判断条件：只要有任一轴的数据就认为有可用数据
      this.noDataAvailable = !this.xData.length && !this.yData.length && !this.zData.length;
      console.log('最终数据可用性状态:', this.noDataAvailable ? '无数据' : '有数据');

      // 记录数据是否有变化
      const hasDataChanged =
        beforeUpdate.xDataLength !== this.xData.length ||
        beforeUpdate.yDataLength !== this.yData.length ||
        beforeUpdate.zDataLength !== this.zData.length;

      console.log('数据是否有变化:', hasDataChanged,
        '之前:', beforeUpdate,
        '之后:', {xDataLength: this.xData.length, yDataLength: this.yData.length, zDataLength: this.zData.length});

      // 如果数据长度为0，但我们期望有数据，则创建一些数据点
      if (this.xData.length === 0 && !this.noDataAvailable) {
        console.log('尝试创建随机测试数据点 (x轴)');
        this.xData = Array(10).fill(0).map(() => Math.random() * 0.5);
      }

      if (this.yData.length === 0 && !this.noDataAvailable) {
        console.log('尝试创建随机测试数据点 (y轴)');
        this.yData = Array(10).fill(0).map(() => Math.random() * 0.5);
      }

      if (this.zData.length === 0 && !this.noDataAvailable) {
        console.log('尝试创建随机测试数据点 (z轴)');
        this.zData = Array(10).fill(0).map(() => Math.random() * 0.5);
      }

      // 如果没有x轴数据，创建默认数据
      if (!this.xAxisData || this.xAxisData.length === 0) {
        console.log('创建默认x轴标签');
        this.xAxisData = Array(Math.max(this.xData.length, this.yData.length, this.zData.length))
          .fill(0)
          .map((_, i) => `点${i + 1}`);
      }

      // 确保图表已初始化，然后更新图表数据
      this.$nextTick(() => {
        // 如果图表为空，尝试重新初始化
        if (!this.mainChart) {
          console.log('图表为空，重新初始化');
          this.initMainChart();
        }

        // 更新图表数据
        this.updateChartData();

        // 额外安全检查：如果图表已初始化但没有显示，尝试强制刷新
        setTimeout(() => {
          if (this.mainChart && !this.noDataAvailable) {
            console.log('强制刷新图表尺寸');
            this.mainChart.resize();
          }
        }, 200);
      });
    },

    initMainChart() {
      if (!this.$refs.mainChart) return;

      // 初始化阈值数据，确保结构完整
      if (!this.thresholds || !this.thresholds.x || !this.thresholds.y || !this.thresholds.z) {
        console.log('初始化图表时设置默认阈值数据');
        this.thresholds = {
          x: { value: 0.5, peakValue: 1.0, color: '#F56C6C' },
          y: { value: 0.5, peakValue: 1.0, color: '#E6A23C' },
          z: { value: 0.5, peakValue: 1.0, color: '#409EFF' }
        };
      }

      this.mainChart = echarts.init(this.$refs.mainChart);

      // 创建视觉映射配置
      const createVisualMap = (axis) => {
        const thresholdValue = this.dataType === 'rms' ?
          this.thresholds[axis].value :
          this.thresholds[axis].peakValue;

        return {
          show: false,
          dimension: 1, // 针对y轴数据
          pieces: [
            { gt: thresholdValue, color: this.thresholds[axis].color }, // 大于阈值的部分用高亮颜色
            { lte: thresholdValue } // 小于等于阈值的部分保持默认颜色
          ]
        };
      };

      const option = {
        animation: false,
        grid: {
          top: 40,
          right: 40,
          bottom: 50,
          left: 60
        },
        legend: {
          data: ['X轴', 'Y轴', 'Z轴'],
          top: 10,
          icon: 'circle',
          textStyle: {
            color: '#333'
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {type: 'cross'},
          formatter: function (params) {
            let result = params[0].axisValue + '<br/>';
            params.forEach(param => {
              if (!param.value) return;

              const value = Array.isArray(param.value) ? param.value[1] : param.value;
              result += `${param.seriesName}: ${value.toFixed(2)} `;

              // 添加阈值比较，增加安全检查防止未定义错误
              let threshold;
              if (this.thresholds) {
                if (param.seriesIndex === 0 && this.thresholds.x) {
                  threshold = this.dataType === 'rms' ? this.thresholds.x.value : this.thresholds.x.peakValue;
                } else if (param.seriesIndex === 1 && this.thresholds.y) {
                  threshold = this.dataType === 'rms' ? this.thresholds.y.value : this.thresholds.y.peakValue;
                } else if (param.seriesIndex === 2 && this.thresholds.z) {
                  threshold = this.dataType === 'rms' ? this.thresholds.z.value : this.thresholds.z.peakValue;
                }
              }

              if (threshold !== undefined && value >= threshold) {
                result += '<span style="color:#F56C6C">超过阈值</span>';
              } else {
                result += '<span style="color:#67C23A">正常</span>';
              }

              result += '<br/>';
            });
            return result;
          }.bind(this)
        },
        dataZoom: [
          {
            type: 'slider',
            xAxisIndex: 0,
            filterMode: 'filter',
            height: 20,
            bottom: 10,
            start: 0,
            end: 100
          },
          {
            type: 'inside',
            xAxisIndex: 0,
            filterMode: 'filter',
            start: 0,
            end: 100
          }
        ],
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: this.xAxisData,
          axisLine: {
            lineStyle: {
              color: '#ccc'
            }
          },
          axisLabel: {
            show: false
          }
        },
        yAxis: {
          type: 'value',
          name: this.dataType === 'rms' ? '均方根值' : '峰值',
          nameTextStyle: {
            padding: [0, 0, 0, 40]
          },
          axisLine: {
            lineStyle: {
              color: '#ccc'
            }
          },
          splitLine: {
            lineStyle: {
              type: 'dashed',
              color: '#eee'
            }
          }
        },
        series: [
          {
            name: 'X轴',
            type: 'line',
            sampling: 'average',
            symbol: 'none',
            itemStyle: {
              color: '#5470c6'
            },
            lineStyle: {
              width: 2,
              shadowColor: 'rgba(0,0,0,0.3)',
              shadowBlur: 3,
              shadowOffsetY: 2
            },
            areaStyle: {
              opacity: 0.1
            },
            data: this.xData.map((value, index) => [index, value]),
            visualMap: createVisualMap('x')
          },
          {
            name: 'Y轴',
            type: 'line',
            sampling: 'average',
            symbol: 'none',
            itemStyle: {
              color: '#91cc75'
            },
            lineStyle: {
              width: 2,
              shadowColor: 'rgba(0,0,0,0.3)',
              shadowBlur: 3,
              shadowOffsetY: 2
            },
            areaStyle: {
              opacity: 0.1
            },
            data: this.yData.map((value, index) => [index, value]),
            visualMap: createVisualMap('y')
          },
          {
            name: 'Z轴',
            type: 'line',
            sampling: 'average',
            symbol: 'none',
            itemStyle: {
              color: '#ee6666'
            },
            lineStyle: {
              width: 2,
              shadowColor: 'rgba(0,0,0,0.3)',
              shadowBlur: 3,
              shadowOffsetY: 2
            },
            areaStyle: {
              opacity: 0.1
            },
            data: this.zData.map((value, index) => [index, value]),
            visualMap: createVisualMap('z')
          }
        ]
      };

      this.mainChart.setOption(option);
    },

    // 更新波形图数据，修改使用新的visualMap方式
    updateChartData() {
      if (!this.mainChart) {
        console.error('无法更新图表：mainChart未初始化');
        this.initMainChart();
        return;
      }

      // 根据模式选择数据源
      let timeData, xData, yData, zData;

      if (this.realtimeMode && this.isRealtimeActive) {
        // 使用实时数据
        timeData = this.realtimeTimeData.map(time => new Date(time).toLocaleTimeString());
        xData = this.realtimeXData;
        yData = this.realtimeYData;
        zData = this.realtimeZData;
      } else {
        // 使用历史数据
        timeData = this.xAxisData;
        xData = this.xData;
        yData = this.yData;
        zData = this.zData;
      }

      // 数据有效性校验：x轴和三轴数据至少有一组非空
      const xAxisValid = Array.isArray(timeData) && timeData.length > 0;
      const xValid = Array.isArray(xData) && xData.length > 0;
      const yValid = Array.isArray(yData) && yData.length > 0;
      const zValid = Array.isArray(zData) && zData.length > 0;
      if (!xAxisValid || (!xValid && !yValid && !zValid)) {
        console.warn('数据为空，跳过图表更新');
        this.noDataAvailable = true;
        return;
      }

      // 创建包含索引的数据，以支持visualMap
      const xDataWithIndex = xData.map((value, index) => [index, value]);
      const yDataWithIndex = yData.map((value, index) => [index, value]);
      const zDataWithIndex = zData.map((value, index) => [index, value]);

      const option = {
        xAxis: {
          data: timeData
        },
        series: [
          {
            name: 'X轴',
            data: xDataWithIndex
          },
          {
            name: 'Y轴',
            data: yDataWithIndex
          },
          {
            name: 'Z轴',
            data: zDataWithIndex
          }
        ]
      };

      try {
        this.mainChart.setOption(option, false);
        this.noDataAvailable = false;

        // 更新阈值可视化
        this.updateChartVisualization();
      } catch (error) {
        console.error('图表更新失败:', error);
        this.noDataAvailable = true;
        this.recreateChart();
      }
    },

    // 重建图表函数
    recreateChart() {
      console.log('尝试重建图表');
      if (this.mainChart) {
        this.mainChart.dispose();
        this.mainChart = null;
      }

      this.$nextTick(() => {
        if (this.$refs.mainChart) {
          this.initMainChart();
          console.log('图表已重建，现在应用数据');

          const option = {
            xAxis: {
              data: this.xAxisData
            },
            series: [
              {
                name: 'X轴',
                data: this.xData,
                markLine: this.generateThresholdMarkLines('x')
              },
              {
                name: 'Y轴',
                data: this.yData,
                markLine: this.generateThresholdMarkLines('y')
              },
              {
                name: 'Z轴',
                data: this.zData,
                markLine: this.generateThresholdMarkLines('z')
              }
            ]
          };

          this.mainChart.setOption(option);
        } else {
          console.error('无法重建图表：DOM元素不存在');
        }
      });
    },

    // 格式化日期
    formatDate(date, simple = false) {
      if (!date) return ''
      const d = new Date(date)
      const year = d.getFullYear()
      const month = String(d.getMonth() + 1).padStart(2, '0')
      const day = String(d.getDate()).padStart(2, '0')
      const hours = String(d.getHours()).padStart(2, '0')
      const minutes = String(d.getMinutes()).padStart(2, '0')
      const seconds = String(d.getSeconds()).padStart(2, '0')

      if (simple) {
        return `${month}-${day} ${hours}:${minutes}`
      } else {
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
      }
    },

    // 优化的刷新数据方法
    refreshData() {
      console.log('【优化刷新】开始刷新数据');

      // 显示当前性能统计
      const stats = this.dataRequestManager.getStats();
      console.log('【性能统计】当前统计信息:', stats);

      // 清除所有缓存，强制重新获取数据
      this.dataRequestManager.clearCache();

      if (this.deviceId) {
        // 重新执行初始化加载流程
        this.performInitialLoad(this.deviceId);
      } else {
        this.$message.warning('无有效设备ID，无法刷新数据');
      }
    },

    // 新增：显示性能统计信息
    showPerformanceStats() {
      const stats = this.dataRequestManager.getStats();
      const message = `
        数据请求性能统计：
        总请求数: ${stats.totalRequests}
        缓存命中数: ${stats.cacheHits}
        重复请求数: ${stats.duplicateRequests}
        重试次数: ${stats.retries || 0}
        超时次数: ${stats.timeouts || 0}
        缓存命中率: ${stats.cacheHitRate}
        重复请求率: ${stats.duplicateRate}
        平均请求时间: ${stats.avgRequestTime}
        缓存大小: ${stats.cacheSize}
      `;

      this.$alert(message, '性能统计', {
        confirmButtonText: '确定',
        type: 'info'
      });

      console.log('【性能统计】详细信息:', stats);
    },

    // 新增：智能选择加载配置 - 根据API文档优化
    getAdaptiveLoadingConfig(deviceId, step = 'initial') {
      // 检查是否为已知的大数据量设备
      const isLargeDataDevice = this.largeDataDevices.includes(deviceId);

      let configKey = 'medium'; // 默认配置

      if (isLargeDataDevice) {
        // 大数据量设备使用更保守的配置
        switch (step) {
          case 'initial':
          case 'basic':
            configKey = 'xlarge'; // 最小数据量 (500点)
            break;
          case 'more':
            configKey = 'large';  // 较小数据量 (1000点)
            break;
          case 'full':
            configKey = 'medium'; // 中等数据量 (2000点)
            break;
        }
      } else {
        // 普通设备使用标准配置
        switch (step) {
          case 'initial':
          case 'basic':
            configKey = 'medium'; // 中等数据量 (2000点)
            break;
          case 'more':
            configKey = 'small';  // 标准数据量 (3000点)
            break;
          case 'full':
            configKey = 'small';  // 标准数据量 (3000点)
            break;
        }
      }

      const config = this.adaptiveLoadingConfig[configKey];
      console.log(`【智能配置】设备${deviceId}，步骤${step}，使用配置${configKey}:`, config);

      // 根据API文档，只需要返回 maxPoints 参数
      return {
        maxPoints: config.maxPoints
      };
    },

    // 修改 detectDeviceDataSize 方法
    async detectDeviceDataSize(deviceId) {
      try {
        console.log('【数据量检测】检测设备数据量:', deviceId);

        // 使用新的时间范围接口快速检测
        const timeRange = await this.getDeviceTimeRangeData(deviceId);

        // 根据时间范围跨度判断数据量大小
        const startDate = timeRange.startDate;
        const endDate = timeRange.endDate;
        const timeDiff = endDate.getTime() - startDate.getTime();
        const daysDiff = timeDiff / (1000 * 3600 * 24);

        console.log('【数据量检测】时间跨度:', daysDiff, '天');

        // 根据时间跨度判断数据量大小
        if (daysDiff > 365) {
          console.log('【数据量检测】检测到超大数据量设备');
          if (!this.largeDataDevices.includes(deviceId)) {
            this.largeDataDevices.push(deviceId);
          }
          return 'xlarge';
        } else if (daysDiff > 180) {
          console.log('【数据量检测】检测到大数据量设备');
          if (!this.largeDataDevices.includes(deviceId)) {
            this.largeDataDevices.push(deviceId);
          }
          return 'large';
        } else if (daysDiff > 30) {
          return 'medium';
        } else {
          return 'small';
        }

      } catch (error) {
        console.warn('【数据量检测】检测失败，默认为大数据量:', error.message);
        // 如果检测失败，保守地认为是大数据量设备
        if (!this.largeDataDevices.includes(deviceId)) {
          this.largeDataDevices.push(deviceId);
        }
        return 'large';
      }
    },
// 获取设备信息
// 获取设备传感器列表 - 根据车床名称获取
// 优化的传感器切换方法
    async switchSensor(position) {
      console.log('【优化传感器切换】切换到传感器:', position);

      // 清除相关缓存
      this.dataRequestManager.clearCache('getDeviceWaveforms');
      this.dataRequestManager.clearCache('getWaveformDataByrangeTime');

      // 更新传感器信息
      this.currentPosition = position;
      this.currentSensorId = this.sensorPositionToIdMap[position];

      // 立即清空旧数据
      this.resetWaveformData();

      // 异步加载新传感器数据
      if (this.currentSensorId) {
        this.loadWaveformDataAsync(this.currentSensorId);
      } else if (this.deviceId) {
        this.loadWaveformDataAsync(this.deviceId);
      }
    },

    // 新增：重置波形数据
    resetWaveformData() {
      this.extraData = {};
      this.timestamps = [];
      this.xData = [];
      this.yData = [];
      this.zData = [];
      this.noDataAvailable = true;
      this.updateDisplayData();
    },
// 直接使用传感器ID作为设备ID调用API获取波形数据
// 优化的传感器列表更新方法
    async updateDevicePositions(latheName, autoSelectFirst = true) {
      if (!latheName) return;

      console.log('【优化位置更新】更新设备位置列表:', latheName);

      try {
        // 使用缓存管理器获取加速度数据
        const response = await this.dataRequestManager.request(
          'getAccelerationData',
          () => getAccelerationData(),
          {}
        );

        if (response.code === 200 && response.data) {
          this.processSensorData(response.data, latheName);

          // 自动选择第一个位置
          if (this.devicePositions.length > 0 && autoSelectFirst && !this.currentPosition) {
            this.currentPosition = this.devicePositions[0];
            this.currentSensorId = this.sensorPositionToIdMap[this.currentPosition];
          }

          console.log(`【优化位置更新】获取到 ${latheName} 的传感器列表:`, this.devicePositions);
        }
      } catch (error) {
        console.error('【优化位置更新】获取设备位置数据失败:', error);
        this.$message.error('获取传感器列表失败');
      }
    },

    // 新增：优化的波形数据获取方法（支持大数据量分批加载）
    async fetchWaveformDataOptimized(deviceId) {
      const sensorId = this.currentSensorId || null;
      const sensorPosition = this.currentPosition || null;

      console.log('【优化波形】获取波形数据:', deviceId, '传感器位置:', sensorPosition, '传感器ID:', sensorId);

      try {
        // 使用智能配置获取数据
        const options = this.getAdaptiveLoadingConfig(deviceId, 'initial');

        const response = await this.dataRequestManager.request(
          'getDeviceWaveforms',
          () => getDeviceWaveforms(deviceId, sensorId, options),
          { deviceId, sensorId }
        );

        return this.processWaveformResponse(response);
      } catch (error) {
        console.error('【优化波形】获取失败:', error);

        // 如果是超时错误，尝试更小的数据量
        if (error.message.includes('超时')) {
          console.log('【优化波形】检测到超时，尝试更小数据量');
          return this.fetchWaveformDataWithFallback(deviceId, sensorId);
        }

        this.handleWaveformError(error);
        throw error;
      }
    },

    // 新增：降级获取波形数据（更小数据量）
    async fetchWaveformDataWithFallback(deviceId, sensorId) {
      try {
        console.log('【降级获取】使用最小数据量获取波形数据');

        // 使用最保守的配置
        const options = this.getAdaptiveLoadingConfig(deviceId, 'basic');

        const response = await this.dataRequestManager.request(
          'getDeviceWaveforms_fallback',
          () => getDeviceWaveforms(deviceId, sensorId, options),
          { deviceId, sensorId, fallback: true }
        );

        this.$message.warning('数据量较大，已加载部分数据。如需完整数据，请使用时间范围查询。');
        return this.processWaveformResponse(response);

      } catch (error) {
        console.error('【降级获取】仍然失败:', error);
        throw error;
      }
    },

    // 新增：优化的历史数据获取方法
    // 修改 fetchAllHistoricalDataOptimized 方法
    async fetchAllHistoricalDataOptimized(sensorId) {
      console.log('【优化历史】获取全部历史数据，sensorId:', sensorId);

      try {
        // 直接使用新接口获取时间范围，不再请求最近一日的数据
        const timeRange = await this.getDeviceTimeRangeData(sensorId);

        // 设置日期范围显示
        this.dateRange = [timeRange.startDate, timeRange.endDate];
        this.loadingProgress = 30;

        console.log('【优化历史】获取到时间范围:', timeRange.startTime, '到', timeRange.endTime);

        // 使用获取到的时间范围直接请求完整历史数据
        const response = await this.dataRequestManager.request(
          'getWaveformDataByrangeTime_full',
          () => {
            // 使用智能配置获取合适的 maxPoints
            const options = this.getAdaptiveLoadingConfig(sensorId, 'full');
            return getWaveformDataByrangeTime(sensorId, timeRange.startTime, timeRange.endTime, null, options);
          },
          { sensorId, startTime: timeRange.startTime, endTime: timeRange.endTime }
        );

        this.loadingProgress = 80;
        await this.handleWaveformResponse(response);
        this.loadingProgress = 100;
        this.$message.success('历史数据加载完成');

      } catch (error) {
        console.error('【优化历史】获取失败:', error);
        this.handleWaveformError(error);
        throw error;
      }
    },

    // 新增：计算时间范围
    calculateTimeRange(historyData) {
      let allTimestamps = [];
      historyData.forEach(item => {
        if (Array.isArray(item.timestamps)) {
          allTimestamps = allTimestamps.concat(item.timestamps);
        }
      });

      if (allTimestamps.length === 0) return null;

      const sorted = allTimestamps.map(t => new Date(t)).sort((a, b) => a - b);
      return {
        start: sorted[0],
        end: sorted[sorted.length - 1],
        startTime: this.formatTimeForApi(sorted[0]),
        endTime: this.formatTimeForApi(sorted[sorted.length - 1])
      };
    },

    // 新增：统一的波形响应处理
    processWaveformResponse(response) {
      if (response.code !== 200 || !response.data) {
        throw new Error('响应数据无效');
      }

      const data = Array.isArray(response.data) ? response.data[0] : response.data;
      if (!data) {
        throw new Error('无数据');
      }

      // 更新数据
      this.extraData = data.extraData || {};
      this.timestamps = data.timestamps || [];
      this.noDataAvailable = false;

      // 更新显示
      this.updateDisplayData();
      console.log('【波形处理】数据更新成功');

      return data;
    },

    fetchWaveformData(deviceId) {
      // 使用传感器ID参数
      const sensorId = this.currentSensorId || null;
      const sensorPosition = this.currentPosition || null;

      console.log('获取波形数据请求开始:', deviceId, '传感器位置:', sensorPosition, '传感器ID:', sensorId);

      // 使用传感器ID获取波形数据，添加智能配置
      const options = this.getAdaptiveLoadingConfig(deviceId, 'initial');

      return getDeviceWaveforms(deviceId, sensorId, options).then(response => {
        console.log('波形数据原始响应:', response);

        if (response.code === 200 && response.data) {
          // 提取波形数据
          const waveformData = response.data;
          console.log('提取到的波形数据长度:', Array.isArray(waveformData) ? waveformData.length : '非数组');
          console.log('波形数据结构:', JSON.stringify(waveformData).substring(0, 200) + '...');

          // 测试：直接使用数据，不过滤
          if (!sensorId && !sensorPosition && waveformData.length > 0) {
            console.log('不使用传感器过滤，直接使用第一条数据');
            this.extraData = waveformData[0].extraData || {};
            this.timestamps = waveformData[0].timestamps || [];
            this.noDataAvailable = false;

            console.log('直接使用的extraData:', JSON.stringify(this.extraData).substring(0, 200) + '...');
            console.log('timestamps长度:', this.timestamps.length);

            // 更新显示数据
            this.updateDisplayData();
            return this.extraData;
          }

          // 如果有传感器位置参数，过滤对应的数据
          if ((sensorPosition || sensorId) && Array.isArray(waveformData) && waveformData.length > 0) {
            console.log('使用传感器进行过滤:', sensorPosition, sensorId);

            // 尝试两种过滤方法
            // 方法1：精确匹配传感器ID或位置
            let filteredData = waveformData.filter(item => {
              // 详细记录每个数据项用于调试
              if (item && (item.sensorId || item.putPlace)) {
                console.log('匹配检查:', item.sensorId, item.putPlace,
                  'vs', sensorId, sensorPosition);
              }

              // 优先匹配传感器ID
              if (sensorId && (item.sensorId === sensorId || item.deviceId === sensorId)) {
                return true;
              }
              // 其次匹配传感器位置
              return sensorPosition && item.putPlace === sensorPosition;
            });

            console.log('精确匹配过滤后数据长度:', filteredData.length);

            // 方法2：如果精确匹配没有结果，尝试模糊匹配
            if (filteredData.length === 0 && (sensorPosition || sensorId)) {
              console.log('尝试模糊匹配');
              filteredData = waveformData.filter(item => {
                return (sensorId && item.sensorId && item.sensorId.toString().includes(sensorId.toString())) ||
                  (sensorId && item.deviceId && item.deviceId.toString().includes(sensorId.toString())) ||
                  (sensorPosition && item.putPlace && item.putPlace.includes(sensorPosition));
              });
              console.log('模糊匹配过滤后数据长度:', filteredData.length);
            }

            // 如果还是没有结果，使用第一条数据
            if (filteredData.length === 0) {
              console.log('过滤后没有数据，使用第一条数据');
              this.extraData = waveformData[0].extraData || {};
              this.timestamps = waveformData[0].timestamps || [];
              this.noDataAvailable = false;
            } else {
              console.log('使用过滤后的数据');
              this.extraData = filteredData[0].extraData || {};
              this.timestamps = filteredData[0].timestamps || [];
              this.noDataAvailable = false;

              console.log('过滤后的extraData:', JSON.stringify(this.extraData).substring(0, 200) + '...');
            }
          } else {
            // 无传感器参数或无需过滤，使用第一条数据
            if (Array.isArray(waveformData) && waveformData.length > 0) {
              console.log('数组格式波形数据，使用第一条');
              this.extraData = waveformData[0].extraData || {};
              this.timestamps = waveformData[0].timestamps || [];
              this.noDataAvailable = false;
            } else if (!Array.isArray(waveformData) && waveformData.extraData) {
              // 处理非数组格式的数据
              console.log('非数组格式波形数据，直接使用');
              this.extraData = waveformData.extraData || {};
              this.timestamps = waveformData.timestamps || [];
              this.noDataAvailable = false;
            } else {
              console.warn('未找到有效波形数据');
              this.extraData = {};
              this.timestamps = [];
              this.noDataAvailable = true;
            }
          }

          // 更新显示数据
          this.updateDisplayData();
          return this.extraData;
        } else {
          console.error('获取波形数据失败:', response);
          this.extraData = {};
          this.timestamps = [];
          this.noDataAvailable = true;
          this.updateDisplayData();
          return {};
        }
      }).catch(error => {
        console.error('获取波形数据异常:', error);
        this.extraData = {};
        this.timestamps = [];
        this.noDataAvailable = true;
        this.updateDisplayData();
        return {};
      });
    },

    // 根据设备ID和时间范围获取波形数据
    fetchWaveformDataByTimeRange(deviceId, startTime, endTime) {
      // 添加传感器ID参数
      const sensorId = this.currentSensorId || null;

      console.log('按时间范围获取波形数据:', deviceId, startTime, endTime, '传感器ID:', sensorId);

      // 使用智能配置获取合适的 maxPoints
      const options = this.getAdaptiveLoadingConfig(deviceId, 'range');

      return getWaveformDataByrangeTime(deviceId, startTime, endTime, sensorId, options).then(response => {
        console.log('时间范围波形数据响应:', response);
        if (response.code === 200 && response.data) {
          // 存储波形数据
          if (Array.isArray(response.data) && response.data.length > 0) {
            this.extraData = response.data[0].extraData || {};
            this.timestamps = response.data[0].timestamps || [];
            this.noDataAvailable = false;
          } else if (response.data && !Array.isArray(response.data)) {
            // 单个对象格式
            this.extraData = response.data.extraData || {};
            this.timestamps = response.data.timestamps || [];
            this.noDataAvailable = false;
          } else {
            // 无数据
            this.extraData = {};
            this.timestamps = [];
            this.noDataAvailable = true;
            this.$message.warning('所选时间范围内无振动历史数据');
          }

          // 更新显示数据
          this.updateDisplayData();
        } else {
          this.extraData = {};
          this.timestamps = [];
          this.noDataAvailable = true;
          this.$message.warning('所选时间范围内无振动历史数据');
        }
      }).catch(error => {
        console.error('按时间范围获取波形数据失败', error);
        this.$message.error('获取波形数据失败');
        this.extraData = {};
        this.timestamps = [];
        this.noDataAvailable = true;
      });
    },
// 重置波形数据 @author qianz
// 更新阈值线
    updateThresholdLines() {
      if (!this.mainChart) return;

      // 确保thresholds对象存在及其属性正确初始化
      if (!this.thresholds) {
        console.warn('阈值数据未初始化');
        this.thresholds = {
          x: {value: 0.5, color: '#67C23A'},
          y: {value: 0.5, color: '#67C23A'},
          z: {value: 0.5, color: '#67C23A'}
        };
      }

      // 确保各个轴的阈值对象都存在
      if (!this.thresholds.x) this.thresholds.x = {value: 0.5, color: '#67C23A'};
      if (!this.thresholds.y) this.thresholds.y = {value: 0.5, color: '#67C23A'};
      if (!this.thresholds.z) this.thresholds.z = {value: 0.5, color: '#67C23A'};

      // 确保三个阈值递增
      if (this.thresholds.x.value >= this.thresholds.y.value) {
        this.thresholds.y.value = this.thresholds.x.value + 0.3;
      }

      if (this.thresholds.y.value >= this.thresholds.z.value) {
        this.thresholds.z.value = this.thresholds.y.value + 0.5;
      }

      // 更新图表配置
      this.mainChart.setOption({
        series: [
          {
            // X轴配置
            markLine: this.generateThresholdMarkLines('x')
          },
          {
            // Y轴配置
            markLine: this.generateThresholdMarkLines('y')
          },
          {
            // Z轴配置
            markLine: this.generateThresholdMarkLines('z')
          }
        ]
      });
    },

    // 生成阈值线配置
    generateThresholdMarkLines(axis) {
      // 现在已经使用visualMap实现高亮，不再需要markLine
      // 但为了兼容现有代码，保留此方法并返回空数据
      return { data: [] };
    },

    // 应用阈值
    applyThresholds() {
      this.updateChartVisualization();
      this.$message.success('已应用阈值设置');
    },

    // 重置阈值
    resetThresholds() {
      // 复制默认阈值的深拷贝以避免引用问题
      this.thresholds = JSON.parse(JSON.stringify(this.defaultThresholds));
      this.updateChartVisualization();
      this.$message.info('已重置阈值设置');
      this.thresholdsDisplayKey = Date.now(); // 更新key以强制刷新
    },

    // 保存阈值为设备默认值
    async saveThresholds() {
      const deviceType = this._getEffectiveDeviceType();

      if (deviceType === 'default') {
        this.$message.error('无法确定有效的设备类型以保存阈值。请确保设备信息中的类型或名称可用于识别设备种类。');
        return;
      }

      const conversionFactor = 1.0;
      const dataToSave = {
        deviceType: deviceType,
        xRmsTh: Math.round(this.thresholds.x.value * conversionFactor),
        xPTh: Math.round(this.thresholds.x.peakValue * conversionFactor),
        yRmsTh: Math.round(this.thresholds.y.value * conversionFactor),
        yPTh: Math.round(this.thresholds.y.peakValue * conversionFactor),
        zRmsTh: Math.round(this.thresholds.z.value * conversionFactor),
        zPTh: Math.round(this.thresholds.z.peakValue * conversionFactor)
        // enableTime: new Date() // 后端 VibrationThreshold 实体中没有此字段的setter
      };

      const loading = this.$loading({
        lock: true,
        text: `正在保存 ${deviceType} 类型的阈值...`,
        spinner: 'el-icon-loading',
        background: 'rgba(255, 255, 255, 0.7)'
      });

      let success = false; // Moved action and success variable declaration outside try block
      let action = '';   // Moved action and success variable declaration outside try block

      try {
        let existingThreshold = null;
        try {
            const response = await getThresholdByDeviceType(deviceType);
            if (response.code === 200 && response.data && response.data.deviceType) { // 确保data和deviceType都存在
                existingThreshold = response.data;
            }
        } catch (e) {
            // 获取失败不一定是错误，可能只是记录不存在 (例如后端对于不存在的类型返回404)
            console.warn(`检查阈值配置 ${deviceType} 时未找到或发生错误:`, e.message);
        }

        if (existingThreshold) {
          // 更新
          action = '更新';
          // 后端PUT接口是根据RequestBody中的deviceType等信息进行更新，不需要显式ID
          const updateResponse = await updateThreshold(dataToSave);
          if (updateResponse.code === 200) {
            success = true;
          }
        } else {
          // 新增
          action = '新增';
          const addResponse = await addThreshold(dataToSave);
          if (addResponse.code === 200) {
            success = true;
          }
        }

        if (success) {
          this.$message.success(`阈值已成功${action}为 ${deviceType} 类型的默认值`);
          // 更新 defaultThresholds 以反映保存成功的值
          this.defaultThresholds = JSON.parse(JSON.stringify(this.thresholds));
          this.thresholdsDisplayKey = Date.now(); // 更新key以强制刷新
        } else {
          this.$message.error(`${action}阈值失败，请检查控制台日志`);
        }
      } catch (error) {
        console.error(`保存阈值 (${action}) 失败:`, error);
        this.$message.error(`保存阈值操作异常 (${action})`);
      } finally {
        loading.close();
      }
    },

    // 新增：从数据库加载默认阈值
    async loadDefaultThresholds() {
      await this.loadDeviceThresholds();
    },

    // 新增：根据设备名称提取设备类型（中文部分）
    getDeviceTypeFromName(deviceName) {
      if (!deviceName || typeof deviceName !== 'string') return 'default'; // 默认类型，增加类型检查
      // 修改正则表达式以提取所有中文字符并连接它们
      const match = deviceName.match(/[\u4e00-\u9fa5]+/g);
      if (match) {
        const derived = match.join('').trim();
        // console.log(`【getDeviceTypeFromName】Input: "${deviceName}", Matches: ${JSON.stringify(match)}, Output: "${derived}"`);
        return derived || 'default'; // 如果连接后为空字符串，也返回 'default'
      }
      // console.log(`【getDeviceTypeFromName】Input: "${deviceName}", No Chinese characters found, Output: "default"`);
      return 'default';
    },

    // 新增：加载设备阈值（用于初始化和"读取数据库默认值"）
    async loadDeviceThresholds() {
      const deviceType = this._getEffectiveDeviceType(); // 使用新的辅助方法

      if (deviceType === 'default') { // 简化条件，因为 _getEffectiveDeviceType 会返回 'default'
        this.$message.info('未能确定当前设备的具体类型，或类型为默认。将使用系统预设阈值。');
        // 可以选择重置为硬编码的默认值或保留当前值
        this.thresholds = JSON.parse(JSON.stringify(this.defaultThresholds));
        this.updateChartVisualization();
        return;
      }

      const loading = this.$loading({
        lock: true,
        text: `正在读取 ${deviceType} 类型的默认阈值...`,
        spinner: 'el-icon-loading',
        background: 'rgba(255, 255, 255, 0.7)'
      });

      try {
        const response = await getThresholdByDeviceType(deviceType);
        if (response.code === 200 && response.data) {
          const backendThresholds = response.data;
          const conversionFactor = 1.0; // 假设后端存储的是放大100倍的整数

          console.log('【loadDeviceThresholds】Backend data received:', JSON.stringify(backendThresholds));

          this.thresholds = {
            x: {
              value: backendThresholds.xRmsTh / conversionFactor,
              peakValue: backendThresholds.xPTh / conversionFactor,
              color: this.thresholds.x.color // 保留前端已选颜色
            },
            y: {
              value: backendThresholds.yRmsTh / conversionFactor,
              peakValue: backendThresholds.yPTh / conversionFactor,
              color: this.thresholds.y.color // 保留前端已选颜色
            },
            z: {
              value: backendThresholds.zRmsTh / conversionFactor,
              peakValue: backendThresholds.zPTh / conversionFactor,
              color: this.thresholds.z.color // 保留前端已选颜色
            }
          };
          console.log('【loadDeviceThresholds】Frontend thresholds object updated:', JSON.parse(JSON.stringify(this.thresholds)));

          this.defaultThresholds = JSON.parse(JSON.stringify(this.thresholds)); // 更新组件的默认值
          this.$message.success(`已加载 ${deviceType} 类型的默认阈值`);
          this.thresholdsDisplayKey = Date.now(); // 更新key以强制刷新
        } else {
          this.$message.warn(`未找到 ${deviceType} 类型的阈值配置，使用当前设置。`);
           // 如果后端没有数据，保留当前前端的阈值或重置为硬编码的默认值
           this.thresholds = JSON.parse(JSON.stringify(this.defaultThresholds));
        }
      } catch (error) {
        console.error('加载阈值失败:', error);
        this.$message.error('加载阈值失败');
        this.thresholds = JSON.parse(JSON.stringify(this.defaultThresholds)); // 出错时，重置
      } finally {
        loading.close();
        this.updateChartVisualization();
        console.log('【loadDeviceThresholds】After updateChartVisualization, thresholds:', JSON.parse(JSON.stringify(this.thresholds)));
      }
    },

    toDowntimeEntry() {
      // 跳转到停机信息录入页面，不传递任何参数
      this.$router.push('/gelly/downtime');
    },
    showMoreDowntimeRecords() {
      // 添加更多停机记录的逻辑
      console.log('更多停机记录')
    },
    // 创建测试图表的调试方法
    createTestChart() {
      console.log('开始创建测试图表');
      const chartElement = this.$refs.mainChart;

      if (!chartElement) {
        console.error('图表容器元素不存在!');
        this.$message.error('图表容器不存在');
        return;
      }

      console.log('图表容器尺寸:',
        '宽度:', chartElement.offsetWidth,
        '高度:', chartElement.offsetHeight);

      // 销毁旧图表实例
      if (this.mainChart) {
        console.log('销毁旧图表实例');
        this.mainChart.dispose();
        this.mainChart = null;
      }

      try {
        console.log('初始化新测试图表');
        this.mainChart = echarts.init(chartElement);

        // 极简测试数据
        const testOption = {
          grid: {
            top: 40,
            right: 20,
            bottom: 40,
            left: 50
          },
          xAxis: {
            type: 'category',
            data: ['测试1', '测试2', '测试3', '测试4', '测试5']
          },
          yAxis: {
            type: 'value'
          },
          series: [{
            name: '测试数据',
            type: 'line',
            data: [5, 20, 36, 10, 10],
            itemStyle: {
              color: '#f00'
            },
            lineStyle: {
              width: 3
            }
          }]
        };

        console.log('设置测试图表选项');
        this.mainChart.setOption(testOption);
        this.$message.success('测试图表已创建');
        console.log('测试图表创建成功');
      } catch (error) {
        console.error('创建测试图表失败:', error);
        this.$message.error('创建测试图表失败:' + error.message);
      }
    },
    // 获取传感器全部历史数据 - 自动计算时间范围 - 优化版 - 增加进度显示
    async fetchAllHistoricalData(sensorId) {
      console.log('【优化加载】获取全部历史数据，sensorId:', sensorId);

      // 重置加载状态和进度
      this.loadingProgress = 0;

      try {
        // 设置为加载完整历史数据模式
        this.loadingCompleteHistory = true;

        // 首先快速获取最近一天的数据，以便快速显示图表
        // 这会让用户有东西可以看，同时我们继续加载更多历史数据
        const now = new Date();
        const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); // 一天前
        const quickStartTime = this.formatTimeForApi(oneDayAgo);
        const quickEndTime = this.formatTimeForApi(now);

        console.log('【优化加载】快速获取最近一天数据:', quickStartTime, '到', quickEndTime);

        // 更新加载状态
        this.loadingProgress = 10;
        this.loadingHistoricalData = true;

        // 同时发起两个请求：一个用于快速显示最近数据，一个用于获取完整历史
        const [quickDataPromise, fullHistoryPromise] = [
          // 1. 快速获取最近数据用于立即显示
          // getWaveformDataByrangeTime(sensorId, quickStartTime, quickEndTime)
          //   .catch(error => {
          //     console.error('【优化加载】快速获取数据失败:', error);
          //     return {code: 500, data: null};
          //   }),

          // 2. 同时获取完整历史数据（会花费更长时间）
          getDeviceWaveforms(sensorId).catch(error => {
            console.error('【优化加载】获取完整历史列表失败:', error);
            return {code: 500, data: null};
          })
        ];

        // 处理快速返回的数据
        const quickDataResponse = await quickDataPromise;
        this.loadingProgress = 30;
        console.log('【优化加载】快速数据已返回:', quickDataResponse.code);

        // 如果快速数据有效，立即显示
        let hasQuickData = false;
        if (quickDataResponse.code === 200 && quickDataResponse.data) {
          console.log('【优化加载】处理快速数据用于立即显示');

          // 处理快速数据
          if (Array.isArray(quickDataResponse.data) && quickDataResponse.data.length > 0) {
            this.extraData = quickDataResponse.data[0].extraData || {};
            this.timestamps = quickDataResponse.data[0].timestamps || [];
            const respThresholds = quickDataResponse.data[0].thresholds;
            if (respThresholds) {
              this.thresholds = {
                x: {
                  value: (respThresholds.x && respThresholds.x.value) || 0.5,
                  color: (respThresholds.x && respThresholds.x.color) || '#67C23A'
                },
                y: {
                  value: (respThresholds.y && respThresholds.y.value) || 0.5,
                  color: (respThresholds.y && respThresholds.y.color) || '#67C23A'
                },
                z: {
                  value: (respThresholds.z && respThresholds.z.value) || 0.5,
                  color: (respThresholds.z && respThresholds.z.color) || '#67C23A'
                }
              };
            } else {
              this.thresholds = {
                x: {value: 0.5, color: '#67C23A'},
                y: {value: 0.5, color: '#67C23A'},
                z: {value: 0.5, color: '#67C23A'}
              };
            }
            hasQuickData = true;
            this.noDataAvailable = false;
          } else if (quickDataResponse.data && !Array.isArray(quickDataResponse.data)) {
            // 单个对象格式
            this.extraData = quickDataResponse.data.extraData || {};
            this.timestamps = quickDataResponse.data.timestamps || [];
            const respThresholds = quickDataResponse.data.thresholds;
            if (respThresholds) {
              this.thresholds = {
                x: {
                  value: (respThresholds.x && respThresholds.x.value) || 0.5,
                  color: (respThresholds.x && respThresholds.x.color) || '#67C23A'
                },
                y: {
                  value: (respThresholds.y && respThresholds.y.value) || 0.5,
                  color: (respThresholds.y && respThresholds.y.color) || '#67C23A'
                },
                z: {
                  value: (respThresholds.z && respThresholds.z.value) || 0.5,
                  color: (respThresholds.z && respThresholds.z.color) || '#67C23A'
                }
              };
            } else {
              this.thresholds = {
                x: {value: 0.5, color: '#67C23A'},
                y: {value: 0.5, color: '#67C23A'},
                z: {value: 0.5, color: '#67C23A'}
              };
            }
            hasQuickData = true;
            this.noDataAvailable = false;
          }

          // 立即更新显示
          if (hasQuickData) {
            console.log('【优化加载】立即更新显示快速数据');
            this.updateDisplayData();
            // 不再弹窗提示，改为使用加载遮罩
            // this.$message.info('显示最近数据，正在加载完整历史...');
          }
        }

        // 更新加载进度
        this.loadingProgress = 50;

        // 等待完整历史数据返回
        const fullHistoryResponse = await fullHistoryPromise;
        this.loadingProgress = 70;
        console.log('【优化加载】完整历史数据已返回:',
          fullHistoryResponse.code,
          Array.isArray(fullHistoryResponse.data) ? fullHistoryResponse.data.length : 0);

        // 处理完整历史数据
        if (fullHistoryResponse.code === 200 && fullHistoryResponse.data &&
          Array.isArray(fullHistoryResponse.data) && fullHistoryResponse.data.length > 0) {

          // 收集所有时间戳
          let allTimestamps = [];
          fullHistoryResponse.data.forEach(item => {
            if (Array.isArray(item.timestamps)) {
              allTimestamps = allTimestamps.concat(item.timestamps);
            }
          });

          if (allTimestamps.length > 0) {
            // 找到最早和最晚的时间
            const sorted = allTimestamps.map(t => new Date(t)).sort((a, b) => a - b);
            const startTime = this.formatTimeForApi(sorted[0]);
            const endTime = this.formatTimeForApi(sorted[sorted.length - 1]);

            // 更新日期范围显示
            this.dateRange = [sorted[0], sorted[sorted.length - 1]];
            console.log('【优化加载】完整历史数据时间范围:', startTime, '到', endTime);

            // 如果时间范围和快速数据不同，则获取完整数据
            if (!hasQuickData ||
              startTime !== quickStartTime ||
              endTime !== quickEndTime) {

              console.log('【优化加载】获取完整历史数据');
              this.loadingProgress = 80;

              const fullDataResponse = await getWaveformDataByrangeTime(sensorId, startTime, endTime)
                .catch(error => {
                  console.error('【优化加载】获取完整历史数据失败:', error);
                  return {code: 500, data: null};
                });

              this.loadingProgress = 90;

              if (fullDataResponse.code === 200 && fullDataResponse.data) {
                console.log('【优化加载】处理完整历史数据');

                // 处理完整数据
                if (Array.isArray(fullDataResponse.data) && fullDataResponse.data.length > 0) {
                  this.extraData = fullDataResponse.data[0].extraData || {};
                  this.timestamps = fullDataResponse.data[0].timestamps || [];
                  const respThresholds = fullDataResponse.data[0].thresholds;
                  if (respThresholds) {
                    this.thresholds = {
                      x: {
                        value: (respThresholds.x && respThresholds.x.value) || 0.5,
                        color: (respThresholds.x && respThresholds.x.color) || '#67C23A'
                      },
                      y: {
                        value: (respThresholds.y && respThresholds.y.value) || 0.5,
                        color: (respThresholds.y && respThresholds.y.color) || '#67C23A'
                      },
                      z: {
                        value: (respThresholds.z && respThresholds.z.value) || 0.5,
                        color: (respThresholds.z && respThresholds.z.color) || '#67C23A'
                      }
                    };
                  }
                  this.noDataAvailable = false;
                } else if (fullDataResponse.data && !Array.isArray(fullDataResponse.data)) {
                  // 单个对象格式
                  this.extraData = fullDataResponse.data.extraData || {};
                  this.timestamps = fullDataResponse.data.timestamps || [];
                  const respThresholds = fullDataResponse.data.thresholds;
                  if (respThresholds) {
                    this.thresholds = {
                      x: {
                        value: (respThresholds.x && respThresholds.x.value) || 0.5,
                        color: (respThresholds.x && respThresholds.x.color) || '#67C23A'
                      },
                      y: {
                        value: (respThresholds.y && respThresholds.y.value) || 0.5,
                        color: (respThresholds.y && respThresholds.y.color) || '#67C23A'
                      },
                      z: {
                        value: (respThresholds.z && respThresholds.z.value) || 0.5,
                        color: (respThresholds.z && respThresholds.z.color) || '#67C23A'
                      }
                    };
                  }
                  this.noDataAvailable = false;
                }

                // 更新显示完整历史数据
                this.updateDisplayData();
                this.$message.success('完整历史数据已加载');
              }
            } else {
              console.log('【优化加载】快速数据已涵盖完整历史范围，无需再次获取');
            }
          }
        }

        // 如果没有数据，显示提示
        if (this.noDataAvailable) {
          console.warn('【优化加载】无数据可用');
          this.$message.warning('未找到历史振动数据');
        } else {
          // 确保图表正确显示
          this.$nextTick(() => {
            setTimeout(() => {
              if (this.mainChart) {
                console.log('【优化加载】强制刷新图表');
                this.recreateChart();
              }
            }, 300);
          });
        }

        // 完成加载
        this.loadingProgress = 100;
        setTimeout(() => {
          this.loadingHistoricalData = false;
          this.loadingProgress = 0;
          // 更新首次加载标记，后续加载将显示"特定时段"而非"完整历史"
          this.FirstTimeLoad = false;
        }, 500); // 延迟消失，让用户能看到100%加载完成

      } catch (error) {
        console.error('【优化加载】获取历史数据异常:', error);
        this.$message.error('获取历史数据失败');
        this.loadingHistoricalData = false;
        this.extraData = {};
        this.timestamps = [];
        this.thresholds = {
          x: {value: 0.5, color: '#67C23A'},
          y: {value: 0.5, color: '#67C23A'},
          z: {value: 0.5, color: '#67C23A'}
        };
        this.noDataAvailable = true;
      }
    },
    // 切换波形图全屏模式
    toggleFullscreen() {
      this.isFullscreen = !this.isFullscreen;

      if (this.isFullscreen) {
        this.enterFullscreen();
      } else {
        this.exitFullscreen();
      }

      // 全屏切换后需要重新调整图表大小
      this.$nextTick(() => {
        setTimeout(() => {
          if (this.mainChart) {
            this.mainChart.resize();
          }
        }, 300);
      });
    },

    // 进入全屏模式
    enterFullscreen() {
      const chartContainer = this.$refs.mainChart;
      if (!chartContainer) return;

      // 保存当前的数据缩放状态，用于双击重置时恢复
      if (this.mainChart) {
        const option = this.mainChart.getOption();
        if (option.dataZoom && option.dataZoom[0]) {
          this.savedZoomState = {
            start: option.dataZoom[0].start,
            end: option.dataZoom[0].end
          };
        }
      }

      // 尝试使用浏览器原生全屏API
      if (chartContainer.requestFullscreen) {
        chartContainer.requestFullscreen();
      } else if (chartContainer.webkitRequestFullscreen) { // Safari
        chartContainer.webkitRequestFullscreen();
      } else if (chartContainer.msRequestFullscreen) { // IE11
        chartContainer.msRequestFullscreen();
      } else {
        // 如果原生API不可用，使用CSS模拟全屏
        document.body.classList.add('wave-fullscreen-mode');
        chartContainer.classList.add('fullscreen-chart');
      }

      // 启用键盘控制
      this.enableKeyboardControl();

      // 添加双击事件监听 - 重置缩放
      chartContainer.addEventListener('dblclick', this.handleChartDoubleClick);

      // 创建大型临时提示元素
      this.showKeyboardHint();

      // 显示操作提示（强调先缩放后移动）
      this.$notify({
        title: '全屏操作使用说明',
        message: '1. 先用 ↑↓ 键放大/缩小波形图\n2. 再用 ←→ 键左右移动查看细节\n3. 双击重置视图\n4. 按ESC键退出全屏',
        type: 'info',
        duration: 8000,
        position: 'top-right'
      });
    },

    // 退出全屏模式
    exitFullscreen() {
      // 尝试使用浏览器原生全屏API退出
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.webkitExitFullscreen) { // Safari
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) { // IE11
        document.msExitFullscreen();
      } else {
        // 移除CSS模拟的全屏
        document.body.classList.remove('wave-fullscreen-mode');
        if (this.$refs.mainChart) {
          this.$refs.mainChart.classList.remove('fullscreen-chart');
        }
      }

      // 移除双击事件监听
      if (this.$refs.mainChart) {
        this.$refs.mainChart.removeEventListener('dblclick', this.handleChartDoubleClick);
      }

      // 禁用键盘控制
      this.disableKeyboardControl();
    },

    // 监听全屏变化事件
    handleFullscreenChange() {
      // 检查当前是否为全屏状态
      const newFullscreenState = !!(document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.mozFullScreenElement ||
        document.msFullscreenElement);

      // 当离开全屏状态时禁用键盘控制
      if (this.isFullscreen && !newFullscreenState) {
        this.disableKeyboardControl();
      }

      this.isFullscreen = newFullscreenState;

      // 重新调整图表大小
      if (this.mainChart) {
        this.mainChart.resize();
      }
    },

    // 启用键盘控制
    enableKeyboardControl() {
      if (this.keyboardControlEnabled) return;

      this.keyboardControlEnabled = true;
      document.addEventListener('keydown', this.handleKeydown);

      console.log('键盘控制已启用');
    },

    // 禁用键盘控制
    disableKeyboardControl() {
      if (!this.keyboardControlEnabled) return;

      this.keyboardControlEnabled = false;
      document.removeEventListener('keydown', this.handleKeydown);

      console.log('键盘控制已禁用');
    },

    // 处理键盘事件
    handleKeydown(event) {
      // 仅在全屏模式下启用键盘控制
      if (!this.isFullscreen || !this.mainChart) return;

      // 阻止默认行为（如页面滚动）
      event.preventDefault();

      // 处理ESC键 - 退出全屏
      if (event.key === 'Escape') {
        this.exitFullscreen();
        return;
      }

      // 获取当前dataZoom状态
      const option = this.mainChart.getOption();
      const dataZoom = option.dataZoom[0];

      // 当前开始和结束百分比位置
      let start = dataZoom.start;
      let end = dataZoom.end;

      // 适应性步长计算 - 基于当前的显示范围
      const currentRange = end - start;
      // 动态计算移动步长 - 小范围时移动更小的步长，大范围时移动更大步长
      const adaptiveMoveStep = Math.max(1, Math.min(5, currentRange / 10));
      // 动态计算缩放步长 - 范围越小，缩放步长越小，确保精细调整
      const adaptiveZoomStep = Math.max(1, Math.min(5, currentRange / 8));

      switch (event.key) {
        case 'ArrowLeft': // 左移
          if (start > 0) {
            start = Math.max(0, start - adaptiveMoveStep);
            end = Math.max(currentRange, end - adaptiveMoveStep);
          }
          break;
        case 'ArrowRight': // 右移
          if (end < 100) {
            end = Math.min(100, end + adaptiveMoveStep);
            start = Math.min(start + adaptiveMoveStep, end - currentRange);
          }
          break;
        case 'ArrowUp': // 放大（缩小范围）
          if (end - start > 5) { // 限制最大缩放级别
            const midPoint = (start + end) / 2;
            const newRange = currentRange - adaptiveZoomStep;
            start = Math.max(0, midPoint - newRange / 2);
            end = Math.min(100, midPoint + newRange / 2);
          }
          break;
        case 'ArrowDown': // 缩小（扩大范围）
          const midPoint = (start + end) / 2;
          const newRange = Math.min(100, currentRange + adaptiveZoomStep);
          start = Math.max(0, midPoint - newRange / 2);
          end = Math.min(100, midPoint + newRange / 2);
          break;
        case 'Home': // Home键 - 回到波形开始
          start = 0;
          end = currentRange;
          break;
        case 'End': // End键 - 跳到波形结束
          end = 100;
          start = end - currentRange;
          break;
        case 'r': // R键 - 重置视图
        case 'R':
          this.resetChartZoom();
          return;
        default:
          return; // 忽略其他按键
      }

      // 平滑动画过渡
      this.mainChart.setOption({
        dataZoom: [{
          start: start,
          end: end,
          realtime: true,
          // 添加动画过渡效果
          animation: {
            duration: 200,
            easing: 'cubicOut'
          }
        }]
      });
    },

    // 处理图表双击 - 重置缩放
    handleChartDoubleClick() {
      if (this.isFullscreen && this.mainChart) {
        this.resetChartZoom();
      }
    },

    // 重置图表缩放
    resetChartZoom() {
      if (!this.mainChart) return;

      // 如果有保存的缩放状态，恢复到保存的状态
      if (this.savedZoomState) {
        this.mainChart.setOption({
          dataZoom: [{
            start: this.savedZoomState.start,
            end: this.savedZoomState.end,
            realtime: true,
            animation: {
              duration: 300,
              easing: 'cubicInOut'
            }
          }]
        });
      } else {
        // 否则重置为默认状态（显示全部数据）
        this.mainChart.setOption({
          dataZoom: [{
            start: 0,
            end: 100,
            realtime: true,
            animation: {
              duration: 300,
              easing: 'cubicInOut'
            }
          }]
        });
      }

      // 显示重置提示
      this.$message({
        message: '波形图视图已重置',
        type: 'success',
        duration: 1500
      });
    },

    // 显示键盘操作提示（大型临时提示）
    showKeyboardHint() {
      // 创建提示元素
      const hintElement = document.createElement('div');
      hintElement.className = 'keyboard-hint-overlay';
      hintElement.innerHTML = `
        <div class="keyboard-hint-content">
          <h3>波形图键盘快捷键</h3>
          <div class="key-instruction">
            <div class="key-group">
              <div class="key">↑</div>
              <div class="key">↓</div>
            </div>
            <div class="instruction">
              <span class="step">第一步</span>
              <span>放大/缩小波形图</span>
              <span class="instruction-detail">先调整到合适的缩放比例</span>
            </div>
          </div>
          <div class="key-instruction">
            <div class="key-group">
              <div class="key">←</div>
              <div class="key">→</div>
            </div>
            <div class="instruction">
              <span class="step">第二步</span>
              <span>左右移动查看波形细节</span>
              <span class="instruction-detail">在缩放后使用效果更佳</span>
            </div>
          </div>
          <div class="close-hint">点击任意位置关闭提示</div>
        </div>
      `;

      // 将提示添加到图表容器中
      const chartContainer = this.$refs.mainChart;
      if (chartContainer) {
        chartContainer.appendChild(hintElement);

        // 点击关闭提示
        hintElement.addEventListener('click', () => {
          if (chartContainer.contains(hintElement)) {
            chartContainer.removeChild(hintElement);
          }
        });

        // 5秒后自动移除提示
        setTimeout(() => {
          if (chartContainer.contains(hintElement)) {
            chartContainer.removeChild(hintElement);
          }
        }, 5000);
      }
    },

    // 替换 updateThresholdLines 方法
    updateChartVisualization() {
      if (!this.mainChart) return;

      // 确保thresholds对象存在及其属性正确初始化
      if (!this.thresholds) {
        console.warn('阈值数据未初始化');
        this.thresholds = {
          x: { value: 0.5, peakValue: 1.0, color: '#F56C6C' },
          y: { value: 0.5, peakValue: 1.0, color: '#E6A23C' },
          z: { value: 0.5, peakValue: 1.0, color: '#409EFF' }
        };
      }

      // 确保各个轴的阈值对象都存在
      if (!this.thresholds.x) this.thresholds.x = { value: 0.5, peakValue: 1.0, color: '#F56C6C' };
      if (!this.thresholds.y) this.thresholds.y = { value: 0.5, peakValue: 1.0, color: '#E6A23C' };
      if (!this.thresholds.z) this.thresholds.z = { value: 0.5, peakValue: 1.0, color: '#409EFF' };

      // 创建视觉映射数组 - 将根据阈值分段显示不同颜色
      const createVisualMap = (axis) => {
        const thresholdValue = this.dataType === 'rms' ?
          this.thresholds[axis].value :
          this.thresholds[axis].peakValue;

        return {
          show: false,
          dimension: 1, // 针对y轴数据
          pieces: [
            { gt: thresholdValue, color: this.thresholds[axis].color }, // 大于阈值的部分用高亮颜色
            { lte: thresholdValue } // 小于等于阈值的部分保持默认颜色
          ]
        };
      };

      // 更新图表配置，仅更新series的visualMap部分
      this.mainChart.setOption({
        series: [
          {
            name: 'X轴', // 匹配 initMainChart 中的 series name
            visualMap: createVisualMap('x')
          },
          {
            name: 'Y轴', // 匹配 initMainChart 中的 series name
            visualMap: createVisualMap('y')
          },
          {
            name: 'Z轴', // 匹配 initMainChart 中的 series name
            visualMap: createVisualMap('z')
          }
        ]
      });
    },

    openHighlightDialog() {
      this.highlightDialogVisible = true;
      this.$nextTick(() => {
        this.initHighlightChart();
      });
    },

    initHighlightChart() {
      if (!this.$refs.highlightChartContainer) {
        console.error("Highlight chart container not found.");
        return;
      }
      if (this.highlightChartInstance) {
        this.highlightChartInstance.dispose();
        this.highlightChartInstance = null;
      }

      this.highlightChartInstance = echarts.init(this.$refs.highlightChartContainer);

      const createVisualMap = (axis) => {
        if (!this.thresholds[axis]) {
            console.warn(`Thresholds for axis ${axis} not defined. Using default visualMap.`);
            return null;
        }
        const thresholdValue = this.dataType === 'rms' ?
          this.thresholds[axis].value :
          this.thresholds[axis].peakValue;

        return {
          show: false,
          dimension: 1,
          pieces: [
            { gt: thresholdValue, color: this.thresholds[axis].color || '#ff0000' },
            { lte: thresholdValue }
          ]
        };
      };

      const generateMarkAreaData = (seriesData, thresholdConfig, dataType, xAxisCategories) => {
        if (!thresholdConfig || seriesData.length === 0 || xAxisCategories.length === 0) {
          return [];
        }
        const thresholdValue = dataType === 'rms' ? thresholdConfig.value : thresholdConfig.peakValue;
        const markAreas = [];
        let inViolation = false;
        let startIndex = -1;

        seriesData.forEach((value, index) => {
          const isAboveThreshold = value > thresholdValue;
          if (isAboveThreshold && !inViolation) {
            inViolation = true;
            startIndex = index;
          } else if ((!isAboveThreshold || index === seriesData.length - 1) && inViolation) {
            // End of a violation segment or end of data while in violation
            const actualEndIndex = isAboveThreshold && index === seriesData.length - 1 ? index : index -1;
            if (startIndex !== -1 && actualEndIndex >= startIndex) {
               // Ensure xAxisCategories has entries for startIndex and actualEndIndex
              if (xAxisCategories[startIndex] && xAxisCategories[actualEndIndex]) {
                markAreas.push([
                  { xAxis: xAxisCategories[startIndex], yAxis: thresholdValue },
                  { xAxis: xAxisCategories[actualEndIndex] }
                ]);
              }
            }
            inViolation = false;
            startIndex = -1;
          }
        });
        return markAreas;
      };

      const markAreaBaseStyle = (color) => ({
        itemStyle: {
          color: color,
          opacity: 0.2 // Adjust opacity for desired effect
        },
        silent: true
      });

      // Prepare markArea data for each axis
      const markAreaDataX = generateMarkAreaData(this.xData, this.thresholds.x, this.dataType, this.xAxisData);
      const markAreaDataY = generateMarkAreaData(this.yData, this.thresholds.y, this.dataType, this.xAxisData);
      const markAreaDataZ = generateMarkAreaData(this.zData, this.thresholds.z, this.dataType, this.xAxisData);

      const option = {
        animation: false,
        grid: { top: 40, right: 40, bottom: 50, left: 60 },
        legend: {
          data: ['X轴', 'Y轴', 'Z轴'],
          top: 10,
          icon: 'circle',
          textStyle: { color: '#333' }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'cross' },
          formatter: function (params) {
            let result = params[0].axisValue + '<br/>';
            params.forEach(param => {
              if (param.value == null) return; // 检查param.value是否为null或undefined

              const value = Array.isArray(param.value) ? param.value[1] : param.value;
               if (value == null) return; // 再次检查确保value有效

              result += `${param.seriesName}: ${value.toFixed(2)} `;

              let threshold;
              let axisName = '';
              if (param.seriesIndex === 0) axisName = 'x';
              else if (param.seriesIndex === 1) axisName = 'y';
              else if (param.seriesIndex === 2) axisName = 'z';

              if (this.thresholds && this.thresholds[axisName]) {
                threshold = this.dataType === 'rms' ? this.thresholds[axisName].value : this.thresholds[axisName].peakValue;
              }

              if (threshold !== undefined && value >= threshold) {
                result += `<span style="color:${this.thresholds[axisName].color || '#F56C6C'}">超过阈值</span>`;
              } else {
                result += '<span style="color:#67C23A">正常</span>';
              }
              result += '<br/>';
            });
            return result;
          }.bind(this)
        },
        dataZoom: [
          { type: 'slider', xAxisIndex: 0, filterMode: 'filter', height: 20, bottom: 10, start: 0, end: 100 },
          { type: 'inside', xAxisIndex: 0, filterMode: 'filter', start: 0, end: 100 }
        ],
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: this.xAxisData, // 使用主图表的数据
          axisLine: { lineStyle: { color: '#ccc' } },
          axisLabel: { show: true } // 在对话框中可以显示X轴标签
        },
        yAxis: {
          type: 'value',
          name: this.dataType === 'rms' ? '均方根值' : '峰值',
          nameTextStyle: { padding: [0, 0, 0, 40] },
          axisLine: { lineStyle: { color: '#ccc' } },
          splitLine: { lineStyle: { type: 'dashed', color: '#eee' } }
        },
        series: [
          {
        name: 'X轴',
        type: 'line',
        sampling: 'average',
        symbol: 'none',
            itemStyle: { color: '#5470c6' }, // 基础颜色
            lineStyle: { width: 2 },
            areaStyle: { opacity: 0.1 },
            data: this.xData.map((val, idx) => [this.xAxisData[idx], val]), // 确保数据格式正确
            visualMap: createVisualMap('x'),
            markArea: { ...markAreaBaseStyle(this.thresholds.x ? this.thresholds.x.color : '#5470c6'), data: markAreaDataX }
          },
          {
        name: 'Y轴',
        type: 'line',
        sampling: 'average',
        symbol: 'none',
            itemStyle: { color: '#91cc75' }, // 基础颜色
            lineStyle: { width: 2 },
            areaStyle: { opacity: 0.1 },
            data: this.yData.map((val, idx) => [this.xAxisData[idx], val]),
            visualMap: createVisualMap('y'),
            markArea: { ...markAreaBaseStyle(this.thresholds.y ? this.thresholds.y.color : '#91cc75'), data: markAreaDataY }
          },
          {
        name: 'Z轴',
        type: 'line',
        sampling: 'average',
        symbol: 'none',
            itemStyle: { color: '#ee6666' }, // 基础颜色
            lineStyle: { width: 2 },
            areaStyle: { opacity: 0.1 },
            data: this.zData.map((val, idx) => [this.xAxisData[idx], val]),
            visualMap: createVisualMap('z'),
            markArea: { ...markAreaBaseStyle(this.thresholds.z ? this.thresholds.z.color : '#ee6666'), data: markAreaDataZ }
          }
        ]
      };
      this.highlightChartInstance.setOption(option);
    },

    handleHighlightDialogClosed() {
      if (this.highlightChartInstance) {
        this.highlightChartInstance.dispose();
        this.highlightChartInstance = null;
      }
      console.log("Highlight chart disposed.");
    },
  }
}
</script>

<style scoped>
.app-container {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  background: linear-gradient(120deg, #f0f6ff 60%, #e6f0ff 100%);
  min-height: 100vh;
  padding: 32px 0;
}

.box-card {
  border-radius: 18px;
  box-shadow: 0 8px 32px 0 rgba(120, 180, 120, 0.10), 0 2px 6px 0 rgba(0, 0, 0, 0.03);
  border: none;
  background: white;
}

.device-info-panel {
  background: linear-gradient(120deg, #f0f6ff 60%, #e6f0ff);
  border-radius: 16px;
  box-shadow: 0 2px 12px 0 rgba(120, 180, 120, 0.08);
  padding: 28px 18px 18px 18px;
  margin-bottom: 18px;
  transition: box-shadow 0.3s;
}

.device-info-panel:hover {
  box-shadow: 0 16px 48px 0 rgba(60, 120, 255, 0.18);
}

.device-header {
  display: flex;
  align-items: center;
  margin-bottom: 18px;
}

.device-name {
  font-size: 1.25rem;
  font-weight: 600;
  color: #3e4d3a;
}

.device-no {
  font-size: 0.95rem;
  color: #7a8c7a;
  margin-top: 2px;
}

.info-list {
  margin-bottom: 18px;
}

.info-item {
  display: flex;
  justify-content: space-between;
  font-size: 1rem;
  margin-bottom: 6px;
}

.label {
  color: #7a8ca6;
}

.value {
  color: #333;
  font-size: 14px;
  font-weight: 500;
}

.status-panel {
  margin-bottom: 18px;
}

.status-tag {
  display: inline-block;
  padding: 4px 18px;
  border-radius: 16px;
  font-size: 1rem;
  font-weight: 600;
  background: linear-gradient(90deg, #e0f7fa 0%, #e3f0ff 100%);
  color: #409EFF;
  margin-bottom: 10px;
  box-shadow: 0 1px 4px 0 rgba(60, 120, 255, 0.08);
  transition: background 0.3s, color 0.3s;
}

.gauge-panel {
  margin-bottom: 10px;
}

.gauge-item {
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 1px 6px 0 rgba(60, 120, 255, 0.06);
  padding: 8px 0 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 8px;
}

.percentage-value {
  font-size: 1.3rem;
  font-weight: bold;
  color: #409EFF;
}

.percentage-label {
  font-size: 0.95rem;
  color: #7a8ca6;
}

.device-details {
  margin-top: 8px;
}

.detail-item {
  font-size: 0.98rem;
  color: #7a8ca6;
  margin-bottom: 2px;
}

.action-bar {
  display: flex;
  justify-content: space-between;
  margin-top: 12px;
}

.wave-select-panel {
  background: #f4f8ff;
  border-radius: 12px;
  padding: 12px 10px 10px 10px;
  margin-top: 18px;
  box-shadow: 0 1px 4px 0 rgba(60, 120, 255, 0.06);
}

.panel-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: #409EFF;
  margin-bottom: 8px;
}

.data-selector {
  display: flex;
  align-items: center;
}

.axis-title {
  font-size: 0.98rem;
  color: #7a8ca6;
  margin-right: 8px;
}

.waveform-panel {
  background: linear-gradient(120deg, #f8fbff 60%, #e3f0ff 100%);
  border-radius: 18px;
  box-shadow: 0 8px 32px 0 rgba(60, 120, 255, 0.10), 0 2px 6px 0 rgba(0, 0, 0, 0.03);
  padding: 24px 24px 18px 24px;
  min-height: 600px;
  position: relative;
  transition: box-shadow 0.3s;
}

.waveform-panel:hover {
  box-shadow: 0 16px 48px 0 rgba(60, 120, 255, 0.18);
}

.waveform-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 18px;
}

.waveform-title {
  font-size: 1.35rem;
  font-weight: 700;
  color: #2d3a4b;
  letter-spacing: 1px;
}

.waveform-controls {
  display: flex;
  align-items: center;
}

/* 波形图下方仪表盘样式 */
.dashboard-panel {
  width: 100%;
  margin-top: 24px;
  padding: 20px;
  border-radius: 14px;
  background: linear-gradient(120deg, #f0f6ff 0%, #e6f0ff 100%);
  box-shadow: 0 2px 12px 0 rgba(60, 120, 255, 0.08);
  animation: fadeInUp 0.8s cubic-bezier(0.23, 1, 0.32, 1);
  position: relative;
}

.dashboard-title {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
  font-size: 18px;
  font-weight: 600;
  color: #2d3a4b;
}

/* 设备维护信息面板样式 */

.maintenance-panel .panel-title {
  display: flex;
  align-items: center;
  font-size: 1.05rem;
  font-weight: 600;
  color: #409EFF;
  margin-bottom: 12px;
}

.maintenance-panel .panel-title i {
  margin-right: 6px;
  font-size: 18px;
}

.info-card-header i {
  margin-right: 5px;
}

.alert-item i {
  color: #E6A23C;
  margin-right: 8px;
}

.no-alerts i {
  margin-right: 8px;
}

/* 添加新的设备形状容器样式 */
.device-shape-container {
  width: 54px;
  height: 54px;
  margin-right: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.device-shape {
  width: 100%;
  height: 100%;
  border-radius: 12px;
  background-color: #f5f7fa;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.device-shape svg {
  width: 100%;
  height: 100%;
}

/* 设备状态样式 */

/* 设备形状变体 */

.device-shape:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* 恢复其余的样式 */
.dashboard-title i {
  margin-right: 8px;
  font-size: 20px;
  color: #409EFF;
}

.dashboard-panel .gauge-panel {
  display: flex;
  justify-content: space-around;
  padding: 10px 0;
  margin-bottom: 0;
}

/* 恢复更多样式... */

.dashboard-panel .gauge-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 15px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.7);
  box-shadow: 0 2px 8px 0 rgba(60, 120, 255, 0.05);
  transition: transform 0.3s, box-shadow 0.3s;
  margin-bottom: 0;
}

.dashboard-panel .gauge-item:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 16px 0 rgba(60, 120, 255, 0.15);
}

.dashboard-panel .percentage-value {
  font-size: 24px;
  font-weight: 700;
  color: #303133;
  line-height: 1;
}

.dashboard-panel .percentage-label {
  display: block;
  margin-top: 8px;
  font-size: 16px;
  color: #606266;
}

.gauge-description {
  margin-top: 12px;
  font-size: 14px;
  color: #909399;
  text-align: center;
}

.waveform-chart {
  width: 100%;
  height: 340px;
  margin-top: 18px;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 2px 12px 0 rgba(60, 120, 255, 0.08);
  animation: fadeInUp 0.8s cubic-bezier(0.23, 1, 0.32, 1);
}

@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translateY(40px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.no-data-tip {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: #b0b8c9;
  font-size: 1.1rem;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  padding: 28px 38px 18px 38px;
  box-shadow: 0 2px 12px 0 rgba(60, 120, 255, 0.08);
  animation: fadeInUp 0.8s cubic-bezier(0.23, 1, 0.32, 1);
}

.no-data-tip .el-icon-warning-outline {
  font-size: 2.2rem;
  color: #f56c6c;
  margin-bottom: 8px;
}

@media (max-width: 1200px) {
  .waveform-panel {
    padding: 12px 6px 8px 6px;
  }

  .device-info-panel {
    padding: 16px 6px 8px 6px;
  }
}

/* 移除播放控制面板样式，添加阈值设置面板样式 */
.threshold-controls {
  background: #fff;
  border-radius: 14px;
  padding: 16px 20px;
  margin-top: 16px;
  box-shadow: 0 2px 12px 0 rgba(60, 120, 255, 0.08);
  animation: fadeInUp 0.5s cubic-bezier(0.23, 1, 0.32, 1);
  border: 1px solid rgba(64, 158, 255, 0.1);
  transition: box-shadow 0.3s ease, transform 0.3s ease;
}

.threshold-controls:hover {
  box-shadow: 0 8px 24px 0 rgba(60, 120, 255, 0.15);
  transform: translateY(-2px);
}

.threshold-controls .panel-title {
  display: flex;
  align-items: center;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 16px;
  border-bottom: 1px solid #ebeef5;
  padding-bottom: 12px;
}

.threshold-controls .panel-title i {
  margin-right: 8px;
  color: #E6A23C;
  font-size: 18px;
}

.threshold-panel-content {
  animation: slideDown 0.3s ease-out;
}

.threshold-settings-container {
  animation: fadeIn 0.4s ease;
}

.device-type-info {
  background: linear-gradient(120deg, #f4f8ff 0%, #e3f0ff 100%);
  padding: 14px 18px;
  border-radius: 10px;
  margin-bottom: 20px;
  color: #444;
  border-left: 4px solid #409EFF;
  font-size: 14px;
  display: flex;
  align-items: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  transition: transform 0.3s ease;
}

.device-type-info:hover {
  transform: translateX(5px);
}

.device-type-info i {
  margin-right: 10px;
  color: #409EFF;
  font-size: 20px;
}

.device-type-info .info-icon {
  margin-left: 8px;
  color: #909399;
  cursor: help;
}

.threshold-tabs {
  margin-bottom: 20px;
}

.custom-tabs {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
  border-radius: 8px;
  overflow: hidden;
}

.threshold-value-container {
  background: #f9fafc;
  padding: 15px;
  border-radius: 8px;
  margin-bottom: 15px;
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.05);
}

.threshold-item {
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  transition: transform 0.2s ease;
}

.threshold-item:hover {
  transform: translateX(5px);
}

.threshold-label {
  min-width: 80px;
  font-size: 14px;
  color: #606266;
  margin-right: 12px;
  font-weight: 500;
}

.threshold-unit {
  margin-left: 8px;
  color: #909399;
  font-size: 13px;
  background: #f0f0f0;
  padding: 2px 6px;
  border-radius: 4px;
}

.threshold-description {
  background-color: #f0f9eb;
  padding: 10px 15px;
  border-radius: 6px;
  color: #67C23A;
  font-size: 13px;
  display: flex;
  align-items: center;
  box-shadow: 0 2px 5px rgba(103, 194, 58, 0.1);
  transition: background-color 0.3s ease;
}

.threshold-description:hover {
  background-color: #e7f6df;
}

.threshold-description i {
  margin-right: 8px;
  font-size: 16px;
}

.threshold-effect-preview {
  display: flex;
  align-items: center;
  margin-top: 15px;
  background: #fff;
  padding: 10px;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.preview-label {
  margin-right: 15px;
  font-size: 14px;
  color: #606266;
  font-weight: 500;
}

.line-preview {
  position: relative;
  width: 150px;
  height: 12px;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.line-normal {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  background-color: #f0f0f0;
  height: 100%;
}

.line-highlight {
  position: absolute;
  left: 0;
  top: 0;
  width: 50%;
  height: 100%;
  transition: background-color 0.3s ease, width 0.3s ease;
}

.line-preview:hover .line-highlight {
  width: 70%;
}

.threshold-actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 20px;
  padding: 15px 0;
  border-top: 1px dashed #ebeef5;
  border-bottom: 1px dashed #ebeef5;
  background: #f9fafc;
  border-radius: 8px;
}

.action-button {
  transition: all 0.3s ease;
  padding: 8px 16px;
  border-radius: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.action-button:hover {
  transform: translateY(-3px);
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
}

.action-button i {
  margin-right: 5px;
}

.apply-btn {
  background: linear-gradient(120deg, #67C23A 0%, #85CE61 100%);
  border-color: #67C23A;
}

.reset-btn {
  background: linear-gradient(120deg, #E6A23C 0%, #F7C552 100%);
  border-color: #E6A23C;
  color: #fff;
}

.save-btn {
  background: linear-gradient(120deg, #409EFF 0%, #53A8FF 100%);
  border-color: #409EFF;
}

.load-btn {
  background: linear-gradient(120deg, #FC427B 0%, #FD79A8 100%);
  border-color: #FC427B;
}

.threshold-info-panel {
  margin-top: 20px;
  background: linear-gradient(120deg, #f4f8ff 0%, #e8f4ff 100%);
  border-radius: 10px;
  padding: 15px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
  transition: box-shadow 0.3s ease;
}

.threshold-info-panel:hover {
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}

.info-title {
  font-weight: 600;
  color: #409EFF;
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid rgba(64, 158, 255, 0.2);
  padding-bottom: 8px;
}

.info-title i {
  margin-right: 8px;
  font-size: 18px;
}

.info-content {
  font-size: 13px;
  color: #606266;
  line-height: 1.6;
}

.info-content p {
  position: relative;
  margin: 8px 0;
  padding-left: 16px;
  transition: transform 0.2s ease;
}

.info-content p:before {
  content: '';
  position: absolute;
  left: 0;
  top: 8px;
  width: 6px;
  height: 6px;
  background-color: #409EFF;
  border-radius: 50%;
}

.info-content p:hover {
  transform: translateX(5px);
  color: #333;
}

.custom-input-number {
  width: 120px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: box-shadow 0.3s ease, transform 0.2s ease;
}

.custom-input-number:hover {
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
  transform: translateY(-2px);
}

.custom-color-picker {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: transform 0.2s ease;
}

.custom-color-picker:hover {
  transform: scale(1.05);
}

.color-preview {
  width: 80px;
  height: 24px;
  border-radius: 12px;
  margin-left: 10px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.color-preview:hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}

.toggle-btn {
  padding: 5px;
  font-size: 16px;
  transition: transform 0.2s ease;
}

.toggle-btn:hover {
  transform: translateY(-2px);
  color: #409EFF;
}

.title-content {
  display: flex;
  align-items: center;
}

.info-icon {
  margin-left: 8px;
  font-size: 14px;
  transition: transform 0.2s ease;
}

.info-icon:hover {
  transform: scale(1.2);
}

.custom-tabs .el-tabs__item {
  padding: 0 15px;
  height: 40px;
  line-height: 40px;
  font-size: 14px;
  color: #606266;
  transition: all 0.3s ease;
}

.custom-tabs .el-tabs__item.is-active {
  color: #409EFF;
  font-weight: 700;
  border-bottom: 2px solid #409EFF;
}

.custom-tabs .el-tabs__item:hover {
  color: #409EFF;
  transform: translateY(-2px);
}

.el-tabs__content {
  padding: 0;
}

.el-tab-pane {
  padding: 20px;
}

.axis-label {
  display: flex;
  align-items: center;
}

.axis-color-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  margin-right: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 恢复关键样式 */
.downtime-panel {
  background: #f4f8ff;
  border-radius: 12px;
  padding: 15px;
  margin-top: 18px;
  margin-bottom: 18px;
  box-shadow: 0 1px 4px 0 rgba(60, 120, 255, 0.06);
  transition: box-shadow 0.3s;
}

.downtime-panel:hover {
  box-shadow: 0 8px 24px 0 rgba(60, 120, 255, 0.15);
}

.downtime-panel .panel-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 1.05rem;
  font-weight: 600;
  color: #409EFF;
  margin-bottom: 12px;
}

.downtime-panel .panel-title > div {
  display: flex;
  align-items: center;
}

.downtime-panel .panel-title i {
  margin-right: 6px;
  font-size: 18px;
}

.downtime-summary {
  display: flex;
  justify-content: space-between;
  margin-bottom: 15px;
}

.downtime-card {
  background: white;
  border-radius: 8px;
  padding: 10px;
  flex: 1;
  margin: 0 5px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  text-align: center;
  transition: transform 0.3s;
}

.downtime-card:first-child {
  margin-left: 0;
}

.downtime-card:last-child {
  margin-right: 0;
}

.downtime-card:hover {
  transform: translateY(-5px);
}

.downtime-value {
  font-size: 1.8rem;
  font-weight: 700;
  color: #409EFF;
  line-height: 1.2;
}

.downtime-unit {
  font-size: 0.9rem;
  font-weight: normal;
  color: #909399;
}

.downtime-label {
  font-size: 0.9rem;
  color: #606266;
  margin-bottom: 5px;
}

.downtime-records {
  background: white;
  border-radius: 8px;
  padding: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.records-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  color: #606266;
}

.record-list {
  max-height: 240px;
  overflow-y: auto;
}

.record-item {
  display: flex;
  padding: 8px 0;
  border-bottom: 1px dashed #ebeef5;
}

.record-item:last-child {
  border-bottom: none;
}

.record-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 10px;
  flex-shrink: 0;
}

.record-icon.maintenance {
  background-color: rgba(103, 194, 58, 0.1);
  color: #67C23A;
}

.record-icon.failure {
  background-color: rgba(245, 108, 108, 0.1);
  color: #F56C6C;
}

.record-icon.other {
  background-color: rgba(144, 147, 153, 0.1);
  color: #909399;
}

.record-info {
  flex: 1;
}

.record-time {
  font-size: 0.95rem;
  font-weight: 600;
  color: #303133;
  margin-bottom: 2px;
}

.record-reason {
  font-size: 0.9rem;
  color: #606266;
  margin-bottom: 2px;
}

.record-date {
  font-size: 0.8rem;
  color: #909399;
}

.no-records i {
  font-size: 24px;
  margin-bottom: 8px;
}

/* 传感器选择样式 */
.sensor-select .axis-title {
  width: 70px;
  font-weight: 500;
  margin-right: 10px;
}

/* 加载数据遮罩层样式 */
.loading-data-overlay {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(255, 255, 255, 0.9);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 10;
  border-radius: 14px;
  backdrop-filter: blur(4px);
  animation: fadeIn 0.3s ease-in-out;
  padding: 30px;
  box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.05);
}

.loading-icon {
  margin-bottom: 20px;
  background: rgba(64, 158, 255, 0.1);
  width: 70px;
  height: 70px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: 0 6px 16px -8px rgba(0, 0, 0, 0.1);
}

.loading-icon i {
  font-size: 36px;
  color: #409EFF;
}

.loading-title {
  font-size: 18px;
  font-weight: bold;
  color: #303133;
  margin-bottom: 10px;
  text-align: center;
}

.loading-description {
  font-size: 15px;
  color: #606266;
  margin-bottom: 20px;
  text-align: center;
  max-width: 80%;
}

.loading-progress {
  width: 70%;
  max-width: 450px;
  text-align: center;
  margin-bottom: 15px;
}

.loading-progress .progress-text {
  display: block;
  margin-top: 6px;
  font-size: 14px;
  color: #409EFF;
  font-weight: 500;
}

.loading-tip {
  margin-top: 15px;
  background-color: #f0f9eb;
  border-radius: 4px;
  padding: 8px 16px;
  font-size: 13px;
  color: #67C23A;
  display: flex;
  align-items: center;
  max-width: 80%;
}

.loading-tip i {
  margin-right: 8px;
  font-size: 16px;
}

/* 全屏模式的样式 */
:fullscreen .waveform-chart {
  height: 90vh !important;
  width: 100% !important;
  background-color: #fff;
  padding: 20px;
  box-sizing: border-box;
}

:-webkit-full-screen .waveform-chart {
  height: 90vh !important;
  width: 100% !important;
  background-color: #fff;
  padding: 20px;
  box-sizing: border-box;
}

:-ms-fullscreen .waveform-chart {
  height: 90vh !important;
  width: 100% !important;
  background-color: #fff;
  padding: 20px;
  box-sizing: border-box;
}

/* 全屏模式下的键盘操作提示 */
@keyframes fadeInOut {
  from {
    opacity: 0.7;
  }
  to {
    opacity: 1;
  }
}

/* 全屏模式临时大型键盘操作提示 */
.keyboard-hint-overlay {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.6);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 100;
  animation: fadeIn 0.3s ease;
}

.keyboard-hint-content {
  background-color: white;
  border-radius: 10px;
  padding: 25px 30px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
  max-width: 500px;
  width: 90%;
}

.keyboard-hint-content h3 {
  text-align: center;
  margin-top: 0;
  margin-bottom: 20px;
  color: #409EFF;
  font-size: 22px;
}

.key-instruction {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
  padding: 10px;
  border-radius: 8px;
  background-color: #f8f9fa;
}

.key-group {
  display: flex;
  margin-right: 20px;
}

.key {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  background-color: #eaeaea;
  border-radius: 6px;
  border: 1px solid #d1d1d1;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-right: 5px;
  font-size: 18px;
  font-weight: bold;
  color: #333;
}

.instruction {
  display: flex;
  flex-direction: column;
}

.step {
  font-weight: bold;
  color: #409EFF;
  margin-bottom: 5px;
}

.instruction-detail {
  font-size: 12px;
  color: #909399;
  margin-top: 3px;
}

.close-hint {
  text-align: center;
  margin-top: 15px;
  padding-top: 10px;
  border-top: 1px dashed #e0e0e0;
  color: #909399;
  font-size: 13px;
  cursor: pointer;
}

/* 按键图标样式 */
.key-icon {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 24px;
  height: 24px;
  background-color: #f0f6ff;
  border-radius: 4px;
  border: 1px solid #d1d1d1;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  margin: 0 2px;
  font-size: 14px;
  font-weight: bold;
  color: #409EFF;
}

/* 自定义提示样式 */
.fullscreen-tooltip .el-tooltip__popper {
  max-width: 300px;
  background-color: white;
  color: #333;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  border: none;
  padding: 15px;
}

.fullscreen-tooltip .popper__arrow:after {
  border-bottom-color: white !important;
}
</style>
